Namelles_One
@Namelles_One
Программист

Тестирование wrapper-а для БД

Давно уж ведется разработка решения для СЭД DocsVision. Часть кода накрыта тестами, в определенный момент появилось желание остановиться, провести рефакторинг всего, что уже написано и накрыть тестами максимум логики.

Проблема в разрывании зависимости с БД. Сейчас взаимодействие с БД выглядит так — получаем объект типа CardData (содержащий в себе словарь всех данных из разных таблиц, составляющих объект Card) и передаем его в сгенерированный класс-wrapper, который предоставляет все данные в виде своих property, используя CardData в качестве низкоуровневого объекта для доступа к БД.

Структура БД является «черным ящиком» и не документирована.

Вопрос — каким образом наиболее правильно уходить от связи с БД в тестах? Вычленить интерфейс каждого wrapper-класса, создать по нему mock-объекты и использовать в реальном коде настоящие объекты, а в вызове через тесты — фейковые? Или возможно как-то проще?

И, откуда брать данные для объектов — заполнять руками в конструкторах для тестов или как?
И так ли плохо использование реальных объектов при тестировании в данном случае — когда структура БД не документирована?
  • Вопрос задан
  • 3105 просмотров
Пригласить эксперта
Ответы на вопрос 3
@LuciferOverLondon
Тоже интересуюсь этим вопросом, но пока не видел особо интересных решений. По ощущениям, хорошо тестируемая связь с БД это ActiveRecord. Либо, более гибко, но с теми же минусами — конструктор запросов (а-ля, для PHP, $db->select()->where()->...).

Основная проблема — потеря гибкости и эффективности: все варианты записи и выборки приходится сводить к тем, которые понимают базовые классы, и которые, соответственно, тестируются. Т.е. не получится использовать для отдельных случаев расширенные фичи СУБД, если они не заложены в методах класса (FORCE INDEX? подзапросы?). ActiveRecord, в случае PHP, ещё и получается накладен для процессора и памяти.

Есть, конечно, вариант реализовать стандартные методы в базовых классах, а для особых случаев определять в классах конкретных объектов и тестировать уже там.

Выборка из нескольких таблиц, как мне кажется, — не принципиальное препятствие для ActiveRecord, т.к. можно определить для этого в коде стандартные средства.

Другой вариант, как развитие конструктора запросов — это собственный язык запросов, вроде того, что есть в Doctrine. У меня не дошло до его использования, но могу предположить, что в свой язык/конструктор можно закладывать последовательно всё больше функционала, бесконечно приближая его к SQL (и, соответственно, идеал — это полностью покрытый тестами парсер нужного диалекта SQL, переводящий запросы в методы языка программирования).

Не знаю, как в .net'е с собственными языками запросов. Слыхал, что там для этого есть нечто под названием LINQ.

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

Если честно, то пока и это не внедрено, а модели ползают в базу даже в тестах. Чтобы тесты выполнялись за разумное время, есть желание поднять базу в памяти, а так как на поддержку фирменных MySQL'евых расширений в каком-нибудь HSQLDB я не рассчитываю, то это будет MySQL на tmpfs.
Ответ написан
Комментировать
@LuciferOverLondon
По поводу «откуда брать данные для объектов — заполнять руками в конструкторах для тестов или как?»

Базу забить можно и автоматически, генерируя объекты/записи со сколько-нибудь адекватными данными. Строки можно генерировать либо просто случайные, либо по словарю, либо — библиотеками для генерации псевдоосмысленных строк (на хабуро недавно пролетала такая в q&a, кажется).

Другое дело, что в тестах вам нужно тестировать поведение кода при определенных условиях, а значит — нужно прямо в них класть в базу то, что будете тестировать. С учетом граничных условий, обработки ошибок и т.д. Следовательно, надо либо прописывать вручную то, что должно попасть в базу перед тестом, либо, если в тесте нужен большой объем данных — сгенерировать его заранее, и переносить, например, из подготовленного xml/json в тестовую базу.
Ответ написан
Комментировать
jonie
@jonie
Есть генераторы данных, например nbuilder.org/.
Кроме того саму базу можно хранить рядом с тестами и подключать во время тестов…
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы