Комментарии 8
"запах кода" по-русски называется говнокодом.
$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 раз, скорее код будет немного другим
По первому пункту полностью согласен.
По второму юнит тест подразумевает полное изолирование от внешней среды. Если передавать что-то еще, даже простые дата-объекты, то это уже не полная изоляция, и тест уже скорее интеграционный.
Интеграционный тест, это такой тест, в котором тестируется что то вам не подконтрольное(БД, внешний API, обращение к datetime хоста), то есть не может выполняться условие что при одних и тех же параметрах(версия php, набор зависимостей), на выходе получаем те же результаты.
Если мы тестируем взаимодействие модулей между собой, при этом нет того, что я описал выше — это все то же юнит-тестирование.
"Не мокайте то, чем вы не владеете", на мой взгляд, странное утверждение.
А если бы сторонний фреймворк предоставлял не обобщенную функцию get(), а давал возможность создавать методы getId(), getAmount(), getPrice() напрямую (аля аннотациями как в Java Spring), то над каждым таким методом надо делать свою обертку и мокать ее?
Я бы перефразировал "Не мокайте обощенные функции, которыми не владеете" и вообще не создавайте свои обобщенные функции. :D
Не мокайте то, чем вы не владеете