Как стать автором
Обновить

Комментарии 7

"запах кода" по-русски называется говнокодом.

$request->expects($this->exactly(3))
        ->method('get')
        ->withConsecutive(
            ['id'],
            ['amount'],
            ['price']
        )
        ->willReturnOnConsecutiveCalls(
            '1',
            '2',
            '3',
        );

Собственно, вся проблема в том, что вот здесь, зачем-то добавляется условие, на порядок вызова. Хотя по факту, условие должно накладываться только на значение входящего аргумента. Я не знаток PHP, но за 10 секунд гугления нашёл, что в PHPUnit есть такая штука returnValueMap, которая, как мне кажется, здесь идеально подойдёт, и избавит от необходимости городить огород.
Вообще, задавать адаптеры для таких штук как HttpRequest, часто, неплохая идея. Но дело тут даже не в тестировании, а в том, что так можно изолироваться от имён параметров в HTTP запросе, и формализовать, от каких именно данных HTTP запроса зависит каждый контроллер. Чтобы понять это, программисту осуществляющему поддержку, будет достаточно взглянуть на интерфейс адаптера, а не лезть в контроллер.
Так что, идея обёрток — скорее правильная. Но вот пример в статье выглядит весьма натянуто.

А если нам приходит форма на 80 полей то надо всего лишь добавить 80 методов.
А еще этот фасад нужен однократно, т.к. вы же не будете его усложнять валидацией параметров? Так что рано или поздно вы построите фасад к фасаду, и это совершенно не пахнет?


А проблема решается просто:


->will($this->returnValueMap($map))

Естественно то, что описано в статье — не серебряная пуля, и все может сильно отличаться от проекта к проекту.


Например — те же 80 полей могут оказаться полями одной сущности — и тогда они прекрасно мапятся на dto, и далее по коду используется уже мок этого самого объекта, вместо класса реквеста.


Плюс сложно представить код, в котором 80 полей из реквеста получаются вручную через get() 80 раз, скорее код будет немного другим

Многие фреймворки позволяют заменить стандартный Request на более специфичный. В Symfony, например, можно использовать ArgumentResolver, что бы в контроллере получить уже провалидированный DTO.

Да и в целом, я не понимаю зачем мокать реквест или любые другие «data class» объекты, ведь можно просто создать сам объект запроса в тесте.

По первому пункту полностью согласен.


По второму юнит тест подразумевает полное изолирование от внешней среды. Если передавать что-то еще, даже простые дата-объекты, то это уже не полная изоляция, и тест уже скорее интеграционный.

Интеграционный тест, это такой тест, в котором тестируется что то вам не подконтрольное(БД, внешний API, обращение к datetime хоста), то есть не может выполняться условие что при одних и тех же параметрах(версия php, набор зависимостей), на выходе получаем те же результаты.
Если мы тестируем взаимодействие модулей между собой, при этом нет того, что я описал выше — это все то же юнит-тестирование.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.