LINUX.ORG.RU

Изолированные интеграционные тесты

 , integration-test, , ,


0

1

В проекте на мавене запускаются интеграционные тесты failsafe плагином. В pre-integration-test docker-maven-plugin запускает контейнер с базой данных, к которой потом подключаются тесты, в post-integration-test, соответственно, останавливает контейнер. Все тесты внутри одного модуля в итоге работают с одной БД и все изменения у них общие и видимы друг для друга. Хотелось бы изолировать их друг от друга.

Из вариантов пока вижу вручную чистить БД в каждом тесте перед его запуском либо каждый тест выносить в отдельный модуль. Может есть ещё какое-то решение?

★★★★★

параллельное ко всему этому размышление: https://github.com/testcontainers

https://www.testcontainers.org/usage/generic_containers.html#example

я пробовал, это работает

т.е. ты не обязан анально завязываться на docker-maven-plugin, который ты еле-еле можешь поднастроить. А стартовать нужную конфигурацию прямо из тестов, и этот старты - три строчки джавакода

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)

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

anonymous
()

Адово тормозить будет в любом случае. Вариант только писать тесты так чтобы они друг друга не ломали. Заодно когда сломают - будет повод искать баги. Но это отрицательно влияет на воспроизводимость.

Deleted
()
Ответ на: комментарий от Deleted

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

anonymous
()
Ответ на: комментарий от anonymous

Это если в тестах нет например test1{insert(«testData»)} и test2{insertIfAbsent(«testData»)}.

Если выполнить test1 -> test2 усё норм. Если наоборот, то test1 скажет «данные уже есть». И оппа.

Даже если чистить данные после теста, то надо следить за номерами секвенсов (и что бы авторы тестов на них не ориентировались), короче, там культура кодирования нужна 8)

А так, да если писать культурно, то проблем нет.

Deleted
()
Ответ на: комментарий от Deleted

Порядок тестов да, в этом случае должен быть одинаков. Но тут не только культура кодирования, надо будет смотреть что делают чужие тесты, плюс никакого переименования тестов, так как это может поломать их порядок.

К тому же там ещё кроме БД поднимаются сервисы, за ними тоже придётся следить. Всё это слишком запутано станет и сложно.

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

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Ну не в тесте, а при подготовке базы к тесту.

Deleted
()
Ответ на: комментарий от stevejobs

Спасибо, вариант. Но кардинально переделывать сейчас наверное не буду, а на будущее надо будет попробовать программно всё пускать.

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от orm-i-auga

надо будет смотреть что делают чужие тесты

по секрету вам скажу, смотреть на чужие тесты - нужно всегда. а культура кодирования - это в том числе и код-ревью

плюс никакого переименования тестов, так как это может поломать их порядок.

с тех пор, как человечество изобрело maven-surefire-plugin, порядок тестов вообще-то перестал быть проблемой

К тому же там ещё кроме БД поднимаются сервисы, за ними тоже придётся следить. Всё это слишком запутано станет и сложно.

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

anonymous
()
Ответ на: комментарий от orm-i-auga

у меня на прошлой работе тесты были скопом все на одной базе. Но там система очень жирный монолит с минимумом зависимостей. Так что работало без проблем.

Deleted
()
Ответ на: комментарий от anonymous

maven-surefire-plugin

Он же для unit-тестов, а не интеграционных.

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

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

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от orm-i-auga

Если тесты будут зависеть друг от друга,

ниет.

Смотри, ты тестируешь создание юзера - создаёшь, потом там же удаляешь. При удаче тест «чистый», то есть не оставляет в базе ничего.

В следующем тесте ты снова создаёшь тогже юзера, но уже логинишься им и что-то там тыкаешь. Потом удаляешь.

Эти тесты не зависят друг от друга, и могут работать на одной базе. Вот если первый тест не будет за собой чистить то всё, хана.

Deleted
()
Ответ на: комментарий от Deleted

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

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от orm-i-auga

Если они совсем сторонние то их лучше «замокать», иначе можно граблей отхватить. Если же они локальные то просто извернуться. Мы вот недавно с докером ковырялись - там поудалять что-то зело интимно. Пришлось делать тесты, с учётом того что предыдущие могут нагадить (то есть, проверять докер перед созданием). Ну коряво, но ничего не поделать.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от orm-i-auga

Он же для unit-тестов, а не интеграционных.

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

anonymous
()

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

Deleted
()

Не осилил в своё время сделать нормально, но общая схема нормального решения такая: есть образ, в котором установлена нужная база, созданы все нужные таблицы и прочая ерунда и созданы некоторые тестовые данные, общие для всех тестов (это удобно, можно это и не делать, конечно). Собственно одна из задач это автоматический билд этого образа, например через flyway. Когда есть этот образ, на каждый тест запускается контейнер, маппится на рандомный порт и тест работает с этой базой. После теста контейнер в лучших традициях докера выкидываются на помойку. Такие тесты можно запускать параллельно. Контейнеры можно запускать через tmpfs, в общем всё вместе даст очень быстрые и параллельные тесты БД.

Legioner ★★★★★
()

А чем in-memory режим H2 не устраивает («jdbc:h2:mem:whatever;DB_CLOSE_DELAY=-1»)? Или расширения конкретной СУБД использованы?

sanwashere ★★
()
Ответ на: комментарий от stevejobs

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

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от Legioner

Я сейчас образ докера с настроенной БД собираю в отдельном модуле docker-maven-plugin'ом, а запускаю где нужно через testcontainers (ну и первый модуль как зависимость подключена, чтобы собирался при необходимости). В итоге на каждый тест при запуске своя чистая подготовленная БД, которую не надо после отработки как-то очищать.

Вот про параллельность не знаю. Докер может запускать независимые параллельные контейнеры из одного образа что ли?

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от Deleted

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

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

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от sanwashere

Сейчас используется jooq и postgre, а его in-memory не запустишь. Там где раньше на jpa было то да, подключал для тестов derby и в принципе большинство кода отрабатывало как надо. А в одном старом проекте, который был на oracle и jdbc без всяких абстракций, я как-то сделал на коленке конвертор oracle-запросов в derby-запросы. Было интересно попробовать, и внезапно оно заработало. До сих пор там иногда такие тесты дописываю.

orm-i-auga ★★★★★
() автор топика
Ответ на: комментарий от orm-i-auga

Вот про параллельность не знаю. Докер может запускать независимые параллельные контейнеры из одного образа что ли?

Конечно может.

Legioner ★★★★★
()
Ответ на: комментарий от orm-i-auga

:) just as expected.

Кстати, разработчики Testcontainers - это обычные живые люди, в т.ч. русскоговорящие. Можно им писать, задавать вопросы

stevejobs ★★★★☆
()
Ответ на: комментарий от orm-i-auga

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.