Где-то в вашей кодовой базе есть строка кода, которая выполняет фактическое действие по подключению к удаленной БД. Эта строка кода 9 раз из 10 является вызовом «встроенного» метода, предоставляемого библиотеками времени выполнения, специфичными для вашего языка и среды. Таким образом, это не «ваш» код, и вам не нужно его тестировать; для целей модульного теста вы можете быть уверены, что этот вызов метода будет выполнен правильно. То, что вы можете и должны по-прежнему тестировать в своем наборе модульных тестов, - это такие вещи, как обеспечение того, чтобы параметры, которые будут использоваться для этого вызова, были такими, как вы ожидаете, например, проверка правильности строки подключения или оператора SQL или имя хранимой процедуры.
Это одна из целей ограничения, заключающегося в том, что модульные тесты не должны покидать «песочницу» времени выполнения и зависеть от внешнего состояния. Это на самом деле довольно практично; Цель модульного теста - убедиться, что код, который вы написали (или собираетесь написать в TDD), ведет себя так, как вы думали. Код, который вы не написали, например, библиотека, которую вы используете для выполнения операций с базой данных, не должен входить в рамки какого-либо модульного теста по той простой причине, что вы его не написали.
В вашем наборе интеграционных тестов эти ограничения ослаблены. Теперь вы можетеСоздавайте тесты, которые касаются базы данных, чтобы убедиться, что код, который вы написали, хорошо сочетается с кодом, которого вы не делали. Однако эти два набора тестов должны оставаться разделенными, потому что ваш набор модульных тестов тем эффективнее, чем быстрее он выполняется (так что вы можете быстро проверить, что все утверждения, сделанные разработчиками относительно их кода, все еще выполняются), и почти по определению, интеграционный тест медленнее на порядок из-за добавленных зависимостей от внешних ресурсов. Позвольте сборщику-боту обрабатывать ваш полный комплект интеграции каждые несколько часов, выполняя тесты, которые блокируют внешние ресурсы, чтобы разработчики не давили друг другу на ноги, выполняя эти же тесты локально. А если ломается сборка, ну и что? Гораздо большее значение уделяется обеспечению того, чтобы сборщик никогда не провалил сборку, чем, вероятно, должно быть.
Теперь, насколько строго вы можете придерживаться этого, зависит от вашей точной стратегии подключения к базе данных и запроса к ней. Во многих случаях, когда вы должны использовать «доступную» среду доступа к данным, такую как объекты ADO.NET SqlConnection и SqlStatement, весь разработанный вами метод может состоять из вызовов встроенных методов и другого кода, который зависит от наличия соединение с базой данных, и поэтому лучшее, что вы можете сделать в этой ситуации, - это смоделировать всю функцию и довериться комплектам тестов интеграции. Это также зависит от того, насколько вы готовы разрабатывать свои классы, чтобы разрешить замену определенных строк кода для целей тестирования (например, предложение Тоби шаблона Template Template, который является хорошим, поскольку он допускает «частичные проверки»).
Если ваша модель персистентности данных опирается на код в вашем слое данных (например, триггеры, хранимые процессы и т. Д.), То просто нет другого способа выполнить код, который вы сами пишете, кроме разработки тестов, которые либо живут внутри слоя данных, либо пересекают граница между временем выполнения вашего приложения и СУБД. По этой причине пурист сказал бы, что эту модель следует избегать в пользу чего-то вроде ORM. Я не думаю, что пошел бы так далеко; даже в эпоху интегрированных в язык запросов и других проверенных компилятором зависимых от домена операций персистентности, я вижу значение в блокировании базы данных только для операций, предоставляемых хранимой процедурой, и, конечно, такие хранимые процедуры должны проверяться с использованием автоматизированных тесты. Но такие тесты не являются юнит- тестами. Они интеграция тесты.
Если у вас есть проблемы с этим различием, оно обычно основывается на высокой важности, придаваемой полному «охвату кода» или «охвату модульного теста». Вы хотите убедиться, что каждая строка вашего кода покрыта модульным тестом. Благородная цель на ее лице, но я говорю, фигня; этот менталитет поддается анти-паттернам, выходящим далеко за рамки этого конкретного случая, таким как написание безошибочных тестов, которые выполняют, но не осуществляютваш код. Эти типы конечных прогонов исключительно ради номеров покрытия более вредны, чем ослабление минимального покрытия. Если вы хотите убедиться, что каждая строка вашей кодовой базы выполняется каким-либо автоматическим тестом, то это просто; при расчете показателей покрытия кода включайте интеграционные тесты. Вы могли бы даже пойти еще дальше и изолировать эти спорные тесты «Itino» («Интеграция только в имени»), и между вашим модульным набором тестов и этой подкатегорией интеграционных тестов (которые все еще должны выполняться достаточно быстро) вы должны быть чертовски опасными почти близко к полному покрытию.