Как стать автором
Обновить

Комментарии 12

Глупость какая.
Хотели протестировать один репозиторий, в итоге заменили один репозиторий на другой репозиторий, и протестировали второй.

Хорошо, второй репозиторий работает.
Вот тест, подтверждающий что второй репозиторий работает, он проходит.
Прекрасно.

А первый сломан, но вы этого не узнаете, пока не запустите тест именно на нём.

Не повторяйте ошибок автора.
Мокайте там, где можно мокать.
Смело запускайте медленные интеграционные тесты там, где уместны именно интеграционные тесты.

Хотели протестировать один репозиторий, в итоге заменили один репозиторий на другой репозиторий, и протестировали второй.

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

Ошибка автора в выборе примера. Но с аргументацией автора против использования моков согласен.

тестирования пользователей репозитория

не очень понимаю разницу на практике.

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

клиенты репозитория вносят изменения в сущности, полученные в выборке.

а) прод сломан, тесты зеленые.
б) вам нужно поддерживать и сопровождать 2 реализации репозитория, вместо одной

Величина этого риска зависит от деталей реализации репозитория. Если типовой набор операций достаточно ограниченный и не часто растёт, то выигрыш в скорости вполне может оправдывать использование фейка. Делается набор тестов на сравнение поведения двух репозиториев. Проводим одинаковый набор манипуляций над сохраняемыми/загружаемыми объектами и проверяем, что репозитории ведут себя одинаково во всех случаях. Если находятся расхождения в поведении - добавляем новый тест, а с его помощью находим и исправляем расхождения.

Такие тесты используют реальную репу и работают медленно, но это ОК. Их число относительно невелико и растёт не очень быстро. Остальные тесты используют быстрый репозиторий (и, возможно, довольно интенсивно), и поэтому их можно создавать много. Они всё равно будут работать быстро и давать профит ко времени выполнения на CI (в сравнении с использованием медленной репы).

Fun fact: я детально разбирал и планировал внедрить подобный подход, когда работал в одной конторе, использующей облачные хранилища. Измерения профайлером показали, что в тестах реально тратилось 99.5% wall time на ожидание взаимодействия с удалённым хранилищем. Т.е., внедрение быстрого фейкового репозитория ускорило бы тесты в десятки раз.

Однако, не стали это внедрять на деле. Ключевая точка риска - слишком широкий набор операций. Мы использовали одновременно и CRUD API, и довольно обширные многотабличные SQL-like запросы (которые ещё и менялись довольно часто). Поэтому внедрить не рискнули.

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

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

одно время было популярно подменять бд на inmemory sqlite в тестах (в рамках доктрины достаточно database_url в .env.test переписать вроде бы).

но там свои подводные, которые быстро вылазят наружу

Та же история - если используются самописные SQL-запросы, специфичные для конкретной продовой БД, то довольно быстро могут проявиться несовместимости движков. Придётся либо поддерживать две версии запросов, либо отказываться от каких-то полезных/удобных конструкций SQL, либо страдать от расхождений.

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

гораздо более быструю реализацию, нежели полноценная реляционная база данных

В чем проблема взять in-memory sqlite?

Главная проблема в том, что это не всегда возможно или добавляет ограничения. Ну и это всё ещё медленнее чем без.

По заголовку я думал тут покажут как in-memory-реализацию СУБД в юнит-тестах заюзать, а тут как обычно абстрагируют хранилище и рабочую его реализацию оставляют непокрытой и недоступной в тестах. Так надоело это, честно говоря.

В связке Node.js + MongoDB + Jest я уже давно просто беру пакет mongodb-memory-server, прописываю его в devDependencies, и в юнит-тестах получаю живую локальную БД без всяких имитаций. Соответственно по части персистентности вообще ничего мокать не приходится, все сложные запросы исполняются реальной СУБД. Задержка пуска - несколько секунд в худшем случае. На текущем небольшом проекте где-то 600 тестов на данный момент написано, исполняется это всё на моей тачке за минуту на реальной in-memory-базе.

Ну да, ну да, без абстрагирования хранилища я не могу подменить реализацию чтобы переехать на другую СУБД. Пойду поплачу, наверное? На практике так переезжать нужно примерно... никогда.

Ужасающе наивно считать, будто целый мир пишет только небольшие проекты на Node.js + MongoDB, не находите?

Не заявлял такого. Собственно, ожидал почитать как подобное делается на других платформах и стеках.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий