Как вы проводите модульное тестирование класса, предназначенного для общения с данными?

У меня есть несколько классов репозитория, которые предназначены для работы с различными типами данных, полученными из интерфейса IRepository.

В реализациях код обращается к источнику данных, будь то каталог XML-файлов, база данных или даже просто кеш. Можно ли надежно выполнить модульное тестирование любой из этих реализаций? Я не вижу, чтобы фиктивная реализация работала, потому что тогда я тестирую только фиктивный код, а не фактический код.


person Arda Xi    schedule 02.05.2010    source источник


Ответы (4)


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

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

Назовете ли вы такие тесты «модульными» тестами или нет, зависит от того, как вы определяете модульные тесты; лично меня не слишком заботят имена, но меня действительно волнуют тесты. В частности, для баз данных это может быть несколько болезненным (особенно если вы хотите иметь возможность запускать тесты параллельно), но, по моему опыту, они также могут быть невероятно ценными.

person Jon Skeet    schedule 02.05.2010

Я думаю, что если вы тестируете код, который действительно сохраняется или запрашивает данные, вы, вероятно, действительно хотите попасть в базу данных.

Это интеграционные тесты, а не модульные тесты.

Вы можете настроить тестовую базу данных, в которой вы знаете состояние данных, и запустить тесты для этого. Возможно, вы также захотите сообщить тестам, что они отличаются от ваших модульных тестов и их не нужно запускать при каждой регистрации (в nUnit вы можете украсить свой тестовый класс атрибутом, говорящим, что его не запускать)

person Paul    schedule 02.05.2010

Вообще говоря, вы не будете модульно тестировать любой код, единственной целью которого является взаимодействие с источником данных. Вы все равно можете автоматически протестировать репозиторий, но такой тест будет интеграционным по определению. Вы, вероятно, не хотите запускать эти тесты как часть ваших сборок «первого прохода», например. настройка базы данных и уборка после себя может занять незначительное количество времени.

Если у вашего репозитория есть другие обязанности (например, реализация шаблона Unit of Work), вы можете захотеть провести их отдельное модульное тестирование.

person Iain Galloway    schedule 02.05.2010

В какой-то момент реализации IRepository вы будете использовать сторонний API, который будет фактически читать/записывать в/из базы данных/файла/xml. Что вы хотите сделать, так это имитировать эти API, чтобы убедиться, что ваш код вызывает правильный API в правильном порядке.

Поэтому, если вы читаете из базы данных, вы можете имитировать SqlConnection и SqlCommand и убедиться, что вы вызываете правильные методы для этих классов. Если вы пишете в поток, вы можете издеваться над потоком и убедиться, что вы его сбрасываете и удаляете (например).

person Igor Zevaka    schedule 02.05.2010