Как вы проводите модульное тестирование класса, предназначенного для общения с данными?
У меня есть несколько классов репозитория, которые предназначены для общения с различными видами данных, полученных из IRepository
интерфейс.
В реализациях код взаимодействует с источником данных, будь то каталог XML-файлов или база данных или даже просто кеш. Возможно ли надежное модульное тестирование любой из этих реализаций? Я не вижу, чтобы фиктивная реализация работала, потому что тогда я тестирую только фиктивный код, а не реальный код.
4 ответа
Нет, вы бы использовали макет, когда вы писали класс, который использует IRepository
, Для реализации IRepository
, вам нужно проверить соответствующий источник данных. Для баз данных это немного болезненно - для файловой системы чуть меньше.
Там, где это возможно, если вы можете выразить свою реализацию в виде потоков или читателей, вы упростите свою жизнь: тесты для этих частей реализации могут идти против источников данных в памяти или потоков из ресурсов в тестовой сборке. Конечно, вам, вероятно, понадобятся некоторые тесты, которые относятся к реальной базе данных или файловой системе, но, надеюсь, меньше.
Назовете ли вы такие тесты "модульными" тестами или нет, зависит от того, как вы определяете юнит-тесты; лично меня не волнуют имена, но мне нужны тесты. В частности, для баз данных это может быть несколько болезненно (особенно если вы хотите иметь возможность выполнять тесты параллельно), но они также могут быть невероятно полезными, по моему опыту.
Вообще говоря, вы не будете модульно тестировать любой код, единственная цель которого - общаться с источником данных. Вы все еще можете автоматически проверять хранилище, но такой тест по определению будет интеграционным тестом. Вы, вероятно, не хотите запускать эти тесты как часть ваших сборок "первого прохода", например, настройка базы данных и очистка после себя могут занять немалое количество времени.
Если у вашего хранилища есть другие обязанности (например, реализация шаблона "Единица работы"), то вы можете захотеть выполнить их модульное тестирование отдельно.
В какой-то момент в реализации IRepository вы будете использовать сторонний API, который фактически будет читать / записывать в / из базы данных / файла /xml. Что вы хотите сделать, так это смоделировать эти API, чтобы убедиться, что ваш код вызывает правильный API в правильном порядке.
Поэтому, если вы читаете из базы данных, вы можете смоделировать SqlConnection и SqlCommand и убедиться, что вы вызываете правильные методы для этих классов. Если вы пишете в поток, вы можете смоделировать поток и убедиться, что вы его сбросили и удалили (например).
Я думаю, что если вы тестируете код, который фактически сохраняет данные или запрашивает данные, вы, вероятно, действительно захотите получить доступ к базе данных.
Это интеграционные тесты, а не юнит-тесты.
Вы можете настроить тестовую базу данных, в которой вы знаете состояние данных, и запустить тесты для этого. Вы, вероятно, также хотите сообщить тестам, что они отличаются от ваших модульных тестов и не требуют запуска при каждой регистрации (в nUnit вы можете украсить свой тестовый класс с помощью атрибута, запрещающего его запуск)