Каков наилучший подход при модульном тестировании модели, которая интегрируется в приложение, тесно связанное с базой данных?
Конкретный сценарий здесь - корзина покупок - я хотел бы иметь возможность проверить добавление, удаление и извлечение товаров из корзины, а также логику ценообразования и т. Д. Все это, на мой взгляд, требует доступа к базе данных, хотя я несколько раз читал, что доступа к базе данных следует избегать.
unit-testing
user1189880
источник
источник
Ответы:
Внедрение зависимостей - один из способов справиться с этим. Вы можете настроить тестовую базу данных для имитации корзины покупок или даже написать некоторый код, который «подтверждает» транзакцию клиента. Затем во время выполнения ваше программное обеспечение выберет, к какому компоненту подключаться.
Только не подключайтесь к производственной базе данных во время тестирования!
источник
В модульном тестировании вы должны определить границу того, что вы тестируете. Модульное тестирование отличается от интеграционного тестирования. Если логика ценообразования не зависит от содержимого корзины, вы тестируете ее отдельно. Если это не так, и все модули тесно связаны, создайте среду тестирования, которая максимально имитирует производительность, и работайте с этим. Я не верю, что короткие пути и симуляции помогают в долгосрочной перспективе.
источник
Модель не должна зависеть от (конкретной) БД. Если он знает только абстрактную БД (читай «интерфейс»), которая передается модели, тогда вы можете заменить БД на фиктивный объект .
источник
У меня была похожая проблема - у меня не было возможности гарантировать, что моя тестовая БД сохранит значения. Так что в будущем я получу, например, другие цены.
Я извлек необходимые данные в небольшой sqlite -DB и использовал эту БД для своих тестов. Test-DB теперь является частью настройки моего юнит-теста.
источник
«Наилучшее» субъективно, но вы можете просто использовать тестовое соединение БД.
Используйте приборы для загрузки некоторых тестовых данных (например, продуктов для покупки), а затем напишите тестовый набор для класса / функции, которую вы хотите протестировать.
источник
Я создал плагин для Symfony 1.4 (PHP) для решения этой проблемы (среди прочих). Он моделируется по принципу работы тестовой среды Django (Python) : среда создает и заполняет отдельную базу данных тестов перед началом каждого теста и уничтожает базу данных тестов после завершения каждого теста.
У меня была пара опасений по поводу этой стратегии, как с точки зрения производительности (если схема не меняется, почему бы просто не очистить данные вместо перестройки всей структуры?), Так и удобства (иногда я хочу проверять базу данных после провал теста, так что не разрушайте его без разбора!), поэтому я выбрал немного другой подход.
Перед выполнением первого теста база данных уничтожается и перестраивается, если с момента последнего теста произошли изменения в модели. Перед каждым последующим выполнением теста данные в базе данных очищаются, но структура не перестраивается (хотя перестройка вручную может быть запущена из теста при необходимости).
Выборочно загружая данные в каждом тесте, можно создать соответствующую среду для этого теста, не мешая последующим тестам. Файлы фикстур также можно использовать повторно, что делает эту задачу намного менее обременительной (хотя это все еще моя наименее любимая часть написания тестов!).
В обеих тестовых средах адаптер базы данных настроен на использование тестового соединения вместо «производственного» соединения для предотвращения повреждения существующих данных при выполнении теста.
источник
Я бы сказал, просто продолжайте и используйте приборы для предварительной загрузки данных. Это то, как фреймворки модульного тестирования работают в целом при тестировании манипуляций с данными.
Но если вы действительно хотите избежать подключения к какой-либо базе данных и придерживаться чрезмерно строгого определения, что модульные тесты не затрагивают ничего вне кода, взгляните на симуляцию объектов - это может дать вам идеи.
Например, вместо удаления SQL непосредственно в код, где он вам нужен, есть способ вызвать метод, который делает только то, что делает этот SQL. Используйте
Person.getPhoneNumber()
, например, вместоSELECT phone_number FROM person WHERE id = <foo>
. Это не только чище и проще для понимания с первого взгляда, но и во время тестирования вы можете смоделировать объект Person, чтобыgetPhoneNumber()
он всегда возвращал555-555-5555
или что-то в этом роде, а не касался базы данных.источник
Это довольно легко сделать с джунитом, если он немного затянут.
«Настройка» должна определять и заполнять набор временных таблиц.
Затем вы можете выполнить модульные тесты для всех функций обновления, вставки, удаления.
Для каждого теста вы вызываете свой метод обновления, а затем запускаете SQL, чтобы проверить ожидаемый результат.
В фазе «демонтажа» вы отбрасываете все столы.
Таким образом, вы всегда запускаете одни и те же тесты для одних и тех же исходных данных. Если вы сохраняете таблицы между тестами, они заканчивают тем, что «загрязняются» неудачными тестами, также непротиворечивый тест «вставки» практически невозможен, так как вам нужно изобретать новые ключи в каждом тесте.
источник