Я занимаюсь TDD уже год, мне это очень нравится, я люблю свои тестовые наборы и все такое. Тем не менее, я заметил, что в последнее время я провожу много проверок. Например, у меня будет служба, в которую будет добавлен репозиторий - в моем модульном тесте я пройду макет репозитория и проверим, что он был вызван в тестируемом методе. Затем я проверил бы, верны ли результаты (в другом тесте). Это определенно "чувствует" неправильно, так как мои модульные тесты теперь очень связаны с деталями реализации. Я слышал, что вы должны проверить «поведение», однако во многих ситуациях это ... ммм - невозможно? Если у тебя естьvoid
Метод, например, вы обычно тестируете побочные эффекты. Я имею в виду, что легко пойти дальше и показать несколько простых код-ката, где это можно продемонстрировать, но ИМХО это не очень хорошо отражается на реальных программах, которые мы пишем. Что я делаю не так? Является ли этот тип тестирования анти-паттерном? Буду признателен за ваше мнение по этому поводу, я все еще немного новичок, когда дело доходит до TDD.
источник
Ответы:
Ну, вы должны пытаться проверить входы и выходы. Вы должны проверять внешне видимое поведение. «Обещания» или «контракт», которые дает ваш класс.
В то же время иногда нет лучшего способа проверить метод, чем сделать то, что вы сказали.
Я думаю, что это делает ваш тест более хрупким, поэтому вам следует избегать тестов, которые основаны на деталях реализации, если это возможно, но это не соглашение "все или ничего". Иногда все в порядке, самое худшее, что происходит, это то, что вы меняете реализацию и должны обновить тест.
источник
Цель теста - ограничить возможные производительные реализации. Убедитесь, что вы накладываете только те ограничения на реализацию, которые вам действительно нужны. Обычно это то, что должна делать ваша программа, а не то, как она это делает.
Поэтому, если, например, ваша служба добавляет что-то в репозиторий, вам следует проверить, что новая запись впоследствии содержится в репозитории, а не что действие add запущено.
Чтобы это работало, вы должны иметь возможность использовать реализацию репозитория (протестированную в другом месте) в тесте службы. Я обнаружил, что использование реальной реализации коллаборатора - это, как правило, хороший подход, потому что это действительно лучшая реализация.
«Но что, если использование реальных реализаций в тесте стоит дорого (например, потому что они требуют ресурсов, которые сложно настроить)? Мне нужно использовать mocks в этом случае, верно?»
В любом случае вам, вероятно, понадобится один интеграционный тест, который проверяет совместимость реальных реализаций. Убедитесь, что этот единственный интеграционный тест - это все, что нужно для тестирования вашего сервиса. Или, другими словами: если служба объединяет множество коллабораторов (и, следовательно, это потенциально сложно проверить), убедитесь, что она не содержит никакой логики. Если это произойдет, и вам потребуется несколько (интеграционных) тестов, вам нужно изменить структуру вашего кода, например, изолировав логику и, следовательно, сделав ее более тестируемой.
Использование насмешек в этом случае облегчает тестирование плохо изолированной логики и, следовательно, скрывает архитектурную проблему . Поэтому не используйте mocks для тестирования плохо структурированного кода, но вместо этого исправьте структуру.
источник
Мои мысли о: «совокупные услуги».
Проверка звонков сделает это, но не принесет особой пользы. Вы просто проверяете свою проводку.
Есть 3 неисключительных других способа:
Расширьте свои тесты для каждой отдельной службы, чтобы она проверяла поведение более высокого уровня. Например, если вы попали в базу данных в памяти в своих модульных тестах службы, поднимите ее на уровень, чтобы вы тестировали службу на предмет фактического значения в БД. Уровень обслуживания находится выше в дереве абстракций, как и ваш тест.
Используйте генерацию кода для создания сервиса напрямую из агрегированных сервисов.
Используйте что-то вроде рефлексии или динамического языка, чтобы сделать то же самое. Например, в Java может быть возможным использовать интерфейс Groovy, который передает вызов напрямую.
Возможно, есть и другие способы сделать это, но простая проверка проводки имеет очень низкую отдачу и жестко свяжет вас с этой реализацией.
источник