Наилучший способ переопределения классов в стороннем модуле

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение zelenin »

nepster писал(а):С другой стороны, очень много идей включая ar одолжили у рельсов, а я честно говоря не разу не видел не рельсы ни то, чтобы их гнобили за сильную связанность.
а вообще видел разработчика на рельсы? и не увидишь - рельсы уйдут в небытие с теми разработчиками, которые 1х лет назад на них начали кодить.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение zelenin »

nepster писал(а): А вот с моделями нужно что-то делать. Так как 90% разработчиков делают 1 модель, 50 сценариев и всю логику туда-же и это в лучшем случае.
вчера на ютубе выложили презентацию чувака. че-то там про ддд итд. рассказывал как он вкорячивал ддд в yii. Модель запихивал в репозиторий, а внутри $repository->save($model) { $model->save(); }. Занавес.
С моделями ничего делать не надо. От АР отказываемся и все. класс с 5 обязанностью в любой вселенной не очень хорошо.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение zelenin »

ElisDN писал(а):
nepster писал(а):Что касается тестирования тут у меня вопросы, зачем тестировать модели, работа которых на 100% ложится на yii.
Как раз об этом призадумался при подготовке своего скринкаста о тестировании. Может я перфекционист, но всё-таки... Вот о чём думал:

С логикой фреймворка проблем нет. Другое дело, когда мы вмешиваем свою логику в процесс сохранения. В модели часто навешаны поведения и прочий код в beforeSave()/afterSave(). Многое работает с changedAttributes и прочим. И надо вызвать $model->save() и проверить, что все timestamps расставлены, поля отфильтрованы, файлы загружены и все счётчики и связи обновлены. В крайнем случае, чтобы элементарно найти баг, что забыли вернуть true из beforeSave() и модель не сохраняется.

Комбинаций для проверки может быть десятки. Сотни раз записывать в базу и вычищать порой долго. Можно вместо вызова save() вручную эмулировать работу фреймворка, дёргая эти методы beforeSave()/afterSave(), beforeDelete()/afterDelete() и расставлять dirtyAttributes, setIsNewRecord и прочее. Или смириться с необходимостью работы с базой. А хотелось бы для ускорения тестов просто заглушить код сохранения или удаления из БД и вызвать save() или delete(), но там в https://github.com/yiisoft/yii2/blob/50 ... d.php#L451 такой код:

Код: Выделить всё

$primaryKeys = static::getDb()->schema->insert($this->tableName(), $values))
И здесь начинаются пляски, что простым PHPUnit мы конкретно для этой модели статический getDb() никак не замокаем. Нужно либо искать библиотеки для мока статики (или самому возиться с рефлекшенами) чтобы как-то замокать этот getDb() или insert(), либо наследоваться от моделей и переопределять insertInternal(), либо подменять глобально весь Yii::$app->db вместе со схемами таблиц и возвращать обратно в каждом setUp()/tearDown(). Тогда и понял, что отвязать от БД или хотя бы замокать save() или delete() в ActiveRecord для тестов - весьма нетривиальная задача.
все верно. модель АР - это не то, что автоматически работает, т.к. в ней есть обязанности, которые могут себя непредсказуемо вести.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

ElisDN писал(а): И здесь начинаются пляски, что простым PHPUnit мы конкретно для этой модели статический getDb() никак не замокаем. Нужно либо искать библиотеки для мока статики (или самому возиться с рефлекшенами) чтобы как-то замокать этот getDb() или insert(), либо наследоваться от моделей и переопределять insertInternal(), либо подменять глобально весь Yii::$app->db вместе со схемами таблиц и возвращать обратно в каждом setUp()/tearDown(). Тогда и понял, что отвязать от БД или хотя бы замокать save() или delete() в ActiveRecord для тестов - весьма нетривиальная задача.

>что простым PHPUnit
так не получится, это же не независимый пакет, думаю адекватный пример https://github.com/yii2tech/ar-linkmany ... se.php#L34

Код: Выделить всё

public $appConfig = [
    'components' => [
        'db' => $this->mock(....),
    ],
]; 
>Тогда и понял, что отвязать от БД или хотя бы замокать save() или delete() в ActiveRecord для тестов - весьма нетривиальная задача.

я бы мокал те методы которые завязаны на db, innerInsert, innerUpdate а то и "глубже", можно просто проверять что на innerUpdate идут "ожидаемые" аттрибуты,

Код: Выделить всё

    public function updateX($value)
    {
        $this->x = $this->x + $value;
        return $this->update(true, ['x']);
    } 
но опять же, если считать, что валидная модель обязана сохраниться, то все тестирование скатывается до валидации, это в случае фанатизма по сценариям
upd http://blog.jayfields.com/2006/12/rails ... sting.html
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение nepster »

zelenin писал(а):
nepster писал(а): А вот с моделями нужно что-то делать. Так как 90% разработчиков делают 1 модель, 50 сценариев и всю логику туда-же и это в лучшем случае.
вчера на ютубе выложили презентацию чувака. че-то там про ддд итд. рассказывал как он вкорячивал ддд в yii. Модель запихивал в репозиторий, а внутри $repository->save($model) { $model->save(); }. Занавес.
С моделями ничего делать не надо. От АР отказываемся и все. класс с 5 обязанностью в любой вселенной не очень хорошо.
AR одна из основных штук Yii. Будет очень сложно от нее отказаться, так как теряется очень жирная часть возможностей yii и наверно проще поменять инструмент, чем в yii отказаться от AR.

Хотя еще вариант инкапсулировать AR и сверху налепить свой слой абстракции. Но опять таки, что проще. Сменить инструмент или шаманить ?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение zelenin »

nepster писал(а):
zelenin писал(а):
nepster писал(а): А вот с моделями нужно что-то делать. Так как 90% разработчиков делают 1 модель, 50 сценариев и всю логику туда-же и это в лучшем случае.
вчера на ютубе выложили презентацию чувака. че-то там про ддд итд. рассказывал как он вкорячивал ддд в yii. Модель запихивал в репозиторий, а внутри $repository->save($model) { $model->save(); }. Занавес.
С моделями ничего делать не надо. От АР отказываемся и все. класс с 5 обязанностью в любой вселенной не очень хорошо.
AR одна из основных штук Yii. Будет очень сложно от нее отказаться, так как теряется очень жирная часть возможностей yii и наверно проще поменять инструмент, чем в yii отказаться от AR.

Хотя еще вариант инкапсулировать AR и сверху налепить свой слой абстракции. Но опять таки, что проще. Сменить инструмент или шаманить ?
отказаться от нее проще простого.
В АР уже все инкапсулировано. еще что-то хочешь туда запихнуть?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение ElisDN »

lynicidn писал(а):>что простым PHPUnit
так не получится, это же не независимый пакет
В ContactFormTest валидация им замокана. Но оно не работает со статическими и непубличными методами.
lynicidn писал(а):я бы мокал те методы которые завязаны на db, innerInsert, innerUpdate а то и "глубже", можно просто проверять что на innerUpdate идут "ожидаемые" аттрибуты,
Тот код как раз из метода insertInternal(). Как Вы его подмените?
lynicidn писал(а):но опять же, если считать, что валидная модель обязана сохраниться, то все тестирование скатывается до валидации, это в случае фанатизма по сценариям
Нам нужно протестировать правильность работы методов beforeX()/afterX() в связке, а не валидации.
И как это применить в PHP?
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

nepster писал(а):
zelenin писал(а):
nepster писал(а): А вот с моделями нужно что-то делать. Так как 90% разработчиков делают 1 модель, 50 сценариев и всю логику туда-же и это в лучшем случае.
вчера на ютубе выложили презентацию чувака. че-то там про ддд итд. рассказывал как он вкорячивал ддд в yii. Модель запихивал в репозиторий, а внутри $repository->save($model) { $model->save(); }. Занавес.
С моделями ничего делать не надо. От АР отказываемся и все. класс с 5 обязанностью в любой вселенной не очень хорошо.
AR одна из основных штук Yii. Будет очень сложно от нее отказаться, так как теряется очень жирная часть возможностей yii и наверно проще поменять инструмент, чем в yii отказаться от AR.

Хотя еще вариант инкапсулировать AR и сверху налепить свой слой абстракции. Но опять таки, что проще. Сменить инструмент или шаманить ?
можно легко костыльнуть, чтобы потом безболезнено переехать, примерно так

Код: Выделить всё

class UserFinder extends Component
{
     public $modelClass;
     public $queryClass;

   public function createQuery() { return new $this->queryClass($this->modelClass)}

    public function createModel() {}
    public function findXxx() {}
}

class Ar extends ActiveRecord
{
    public static function instantiate($row)
    {
        return Yii::$app->get('userFinder')->createModel();
    }
    public static function find()
    {
        return Yii::$app->get('userFinder')->createQuery();
    }
}
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

ElisDN писал(а):
lynicidn писал(а):>что простым PHPUnit
так не получится, это же не независимый пакет
В ContactFormTest валидация им замокана. Но оно не работает со статическими и непубличными методами.
про какие статические методы идет речь?
ElisDN писал(а):
lynicidn писал(а):я бы мокал те методы которые завязаны на db, innerInsert, innerUpdate а то и "глубже", можно просто проверять что на innerUpdate идут "ожидаемые" аттрибуты,
Тот код как раз из метода insertInternal(). Как Вы его подмените?
не понимаю сути проблемы $mock = $this->getMock('AR', array('insertInternal'));
ElisDN писал(а):
lynicidn писал(а):но опять же, если считать, что валидная модель обязана сохраниться, то все тестирование скатывается до валидации, это в случае фанатизма по сценариям
Нам нужно протестировать правильность работы методов beforeX()/afterX() в связке, а не валидации.
мы возвращаемся опять к проблеме их перекрытия или тестирования метода beforeSave ? $mock->exactly() конкретный пример я бы запросил, но времени не будет вам писать тест, но проблемы все вымышленные у вас
ElisDN писал(а):
И как это применить в PHP?
а это вы сравниваете с рельсами, вот и смотрите что тестируют в рельсках, конечно статейка так себе, но инфы в гугле мало по тестированию ар
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение ElisDN »

lynicidn писал(а):можно легко костыльнуть, чтобы потом безболезнено переехать
Куда переехать? На MongoDB или Redis?
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

ElisDN писал(а):
lynicidn писал(а):можно легко костыльнуть, чтобы потом безболезнено переехать
Куда переехать? На MongoDB или Redis?
на какой нить репозиторий + дата маппер

http://www.design-pattern.ru/
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение ElisDN »

lynicidn писал(а):про какие статические методы идет речь?
Про self::getDb()
lynicidn писал(а):не понимаю сути проблемы $mock = $this->getMock('AR', array('insertInternal'));
1) Методы beforeSave() и afterSave() дергаются внутри insertInternal(). Можно переопределить анонимкой, но...
2) Ваш мок всё равно нерабочий, так как insertInternal() там protected.
lynicidn писал(а):мы возвращаемся опять к проблеме их перекрытия или тестирования метода beforeSave ? $mock->exactly()
Нужно протестировать процесс сохранения модели БЕЗ фактического сохранения её в базу.
lynicidn писал(а):конкретный пример я бы запросил, но времени не будет вам писать тест, но проблемы все вымышленные у вас
Я и не сомневаюсь, что не напишете. Вы по DI мне недавно два треда пустозвонили, что Yii из коробки всё может и всё-всё-всё умеет. В итоге также тихо слились.
lynicidn писал(а):а это вы сравниваете с рельсами, вот и смотрите что тестируют в рельсках, конечно статейка так себе, но инфы в гугле мало по тестированию ар
Я? С рельсами?
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

>Про self::getDb()
писал уже! где не надо юзаете контейнер, где надо теряетесь
>1) Методы beforeSave() и afterSave() дергаются внутри insertInternal(). Можно переопределить анонимкой, но...
не понял опять смысла анонимки
>2) Ваш мок всё равно нерабочий, так как insertInternal() там protected.
от вас чтото скрыли
>Нужно протестировать процесс сохранения модели БЕЗ фактического сохранения её в базу.
до сейв дошло - значит тру, глубже можно оперделять вплоть до аттрибутов, тоже проходили выше
>Я и не сомневаюсь, что не напишете. Вы по DI мне недавно два треда пустозвонили, что Yii из коробки всё может и всё-всё-всё умеет. В итоге также тихо слились.
no comments, пруф, может потерял

>Я? С рельсами?
ссылка была вам только адресована или у нас дебаты?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение ElisDN »

lynicidn писал(а):от вас чтото скрыли
Попробовал ещё раз. Теперь работает :)

Видимо за три месяца что-то изменилось. Вопрос по мокам закрыт:

Код: Выделить всё

use tests\codeception\backend\unit\TestCase;
use yii\db\ActiveRecord;

/**
 * @property integer $id
 * @property integer $value
 */
class User extends ActiveRecord {}

class MockARTest extends TestCase
{
    public function testSchemaInsertCallbackMock()
    {
        $originalDb = Yii::$app->get('db');

        $schema = $this->getMock('yii\db\mysql\Schema', ['insert', 'getTableSchema']);
        $schema->expects($this->atLeastOnce())->method('insert')->will($this->returnValue(['id' => 15]));
        $schema->expects($this->atLeastOnce())->method('getTableSchema')->will($this->returnCallback(function () {
            return new yii\db\TableSchema([
                'name' => 'user',
                'fullName' => 'user',
                'primaryKey' => ['id'],
                'foreignKeys' => [],
                'columns' => [
                    'id' => new yii\db\ColumnSchema([
                        'name' => 'id',
                        'type' => 'integer',
                        'phpType' => 'integer',
                        'dbType' => 'int(11)',
                        'size' => 11,
                        'precision' => 11,
                        'isPrimaryKey' => 1,
                        'autoIncrement' => 1,
                    ]),
                    'value' => new yii\db\ColumnSchema([
                        'name' => 'id',
                        'type' => 'integer',
                        'phpType' => 'integer',
                        'dbType' => 'int(11)',
                        'size' => 11,
                        'precision' => 11,
                        'isPrimaryKey' => 0,
                        'autoIncrement' => 0,
                    ]),
                ],
            ]);
        }));

        $db = $this->getMock('\yii\db\Connection', ['getSchema']);
        $db->expects($this->atLeastOnce())->method('getSchema')->will($this->returnValue($schema));
        $db->expects($this->never())->method('createCommand')->will($this->returnValue(null));

        Yii::$app->set('db', $db);

        $model = new User();
        $model->value = 12;

        $this->assertTrue($model->save());
        $this->assertEquals(15, $model->id);

        Yii::$app->set('db', $originalDb);
    }
} 
Последний раз редактировалось ElisDN 2016.01.21, 12:53, всего редактировалось 1 раз.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

так не пойдет, упоролся ты, а виноват получаюсь я, ты мне дай цитату, где я писал, что "уии всевсевсе может" и где я "слился" не дав тебе ответа
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

и за 3 месяца это не изменилось, вы не представляете себе как устроен и как работает мок, что у него внутри, за счет чего он достигает переопределения и прочие такие мелочи. Есть такое понятие хватать вершки...
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение ElisDN »

lynicidn писал(а):ты мне дай цитату, где я писал, что "уии всевсевсе может" и где я "слился" не дав тебе ответа
viewtopic.php?f=19&t=34676&p=176832#p176815
viewtopic.php?f=26&t=34859&start=40#p177396
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение zelenin »

ElisDN писал(а):
lynicidn писал(а):ты мне дай цитату, где я писал, что "уии всевсевсе может" и где я "слился" не дав тебе ответа
viewtopic.php?f=19&t=34676&p=176832#p176815
viewtopic.php?f=26&t=34859&start=40#p177396
оттуда же кстати подтред про теги сервисов - к вопросу о вершках)
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

ElisDN писал(а):
lynicidn писал(а):ты мне дай цитату, где я писал, что "уии всевсевсе может" и где я "слился" не дав тебе ответа
viewtopic.php?f=19&t=34676&p=176832#p176815
viewtopic.php?f=26&t=34859&start=40#p177396
если я пишу, что "yii так не может" или это не "yii подход" или еще какието "костыли" и объявляю их онными - это не означает, что я имел ввиду, что уии все может, вообще не вижу здесь логики

ссылок можно много накидать, за слова надо отвечать более конструктивно, а не "сливаться"
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Наилучший способ переопределения классов в стороннем модуле

Сообщение lynicidn »

zelenin писал(а):
ElisDN писал(а):
lynicidn писал(а):ты мне дай цитату, где я писал, что "уии всевсевсе может" и где я "слился" не дав тебе ответа
viewtopic.php?f=19&t=34676&p=176832#p176815
viewtopic.php?f=26&t=34859&start=40#p177396
оттуда же кстати подтред про теги сервисов - к вопросу о вершках)
я все равно не понял твой тред про теги, теггируют схожие реализации, чтобы потом им можно было чтото скармливать, я не применял их на практике, только не понял откуда выводы про "вершки" - как раз для чего теги нужны я знаю
Ответить