Тестирование со всеми имеющимися зависимостями все еще важно, но это больше в области интеграционного тестирования, как сказал Джеффри Фауст.
Одним из наиболее важных аспектов модульного тестирования является обеспечение надежности ваших тестов. Если вы не верите, что проходной тест действительно означает, что все хорошо, а неудачный тест действительно означает проблему в рабочем коде, ваши тесты не настолько полезны, как могли бы.
Чтобы сделать ваши тесты заслуживающими доверия, вам нужно сделать несколько вещей, но я собираюсь сосредоточиться только на одном для этого ответа. Вы должны убедиться, что они просты в запуске, чтобы все разработчики могли легко их запустить, прежде чем регистрировать код. «Простота запуска» означает, что ваши тесты выполняются быстро, и для их запуска не требуется обширная конфигурация или настройка. В идеале, любой должен иметь возможность проверить последнюю версию кода, сразу запустить тесты и убедиться, что они пройдены.
Абстрагирование от зависимостей от других вещей (файловая система, база данных, веб-сервисы и т. Д.) Позволяет избежать необходимости конфигурирования и делает вас и других разработчиков менее восприимчивыми к ситуациям, когда возникает искушение сказать: «О, тесты не пройдены, потому что я не сетевой ресурс не настроен. Ладно. Я запусту их позже. "
Если вы хотите проверить, что вы делаете с некоторыми данными, ваши модульные тесты для этого кода бизнес-логики не должны заботиться о том, как вы получаете эти данные. Возможность протестировать основную логику вашего приложения, не завися от поддержки таких вещей, как базы данных, потрясающая. Если вы этого не делаете, вы пропускаете.
PS Я должен добавить, что определенно можно переоценить во имя тестируемости. Тест-драйв вашего приложения помогает смягчить это. Но в любом случае, плохие реализации подхода не делают подход менее актуальным. Что-нибудь может быть использовано неправильно и перестараться, если не продолжать спрашивать "почему я это делаю?" пока развивается.
Что касается внутренних зависимостей, все становится немного мутным. Мне нравится думать о том, что я хочу максимально защитить свой класс от изменений по неправильным причинам. Если у меня есть настройки, как-то так ...
public class MyClass
{
private SomeClass someClass;
public MyClass()
{
someClass = new SomeClass();
}
// use someClass in some way
}
Мне вообще все равно, как SomeClassсоздается. Я просто хочу использовать это. Если SomeClass изменяется и теперь требует параметров для конструктора ... это не моя проблема. Мне не нужно менять MyClass, чтобы учесть это.
Теперь это касается дизайна. Что касается юнит-тестов, я также хочу защитить себя от других классов. Если я тестирую MyClass, мне нравится знать, что внешних зависимостей нет, что SomeClass в какой-то момент не вводил соединение с базой данных или какую-то другую внешнюю ссылку.
Но еще большая проблема заключается в том, что я также знаю, что результаты некоторых моих методов основаны на выводе некоторых методов в SomeClass. Без насмешек или заглушения SomeClass у меня не было бы возможности изменить этот вклад в спрос. Если мне повезет, я смогу составить свою среду внутри теста таким образом, чтобы он вызывал правильный ответ от SomeClass, но такой путь привносит сложность в мои тесты и делает их хрупкими.
Переписав MyClass, чтобы он принимал экземпляр SomeClass в конструкторе, я могу создать поддельный экземпляр SomeClass, который возвращает желаемое значение (либо через фальшивый фреймворк, либо с помощью ручного макета). Мне обычно не нужно вводить интерфейс в этом случае. Делать это или нет - это во многом личный выбор, который может быть продиктован вашим языком выбора (например, интерфейсы более вероятны в C #, но вам определенно не нужен в Ruby).