Почему JUnit 5 выполняет тесты в произвольном порядке?

Для тестирования использую JUnit 5 и базу данных H2. По логике JUnit занимается модульным тестированием, следовательно методы теста не должны зависеть друг от друга. Плюс ко всему JUnit запускает методы тестирования в произвольном порядке.

Тогда возникает парадокс. Если в каком-то методе происходит удаление записи из БД, а в другом пойдет обращение к этой записи, которая уже была удалена, как быть?

Привожу пример. Один метод проводит проверку по поводу удаления записи из таблицы БД по id. Другой метод должен прочитать эту запись по id.

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

UPDATE 1
Благодаря комментарию пользователя @andreymal

Можно объявить аннотации на тестовом классе:

import org.springframework.test.annotation.DirtiesContext;

@Sql(scripts = "classpath:db/schema.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "classpath:db/data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)

Ответы (1 шт):

Автор решения: Roman Konoval

Нет здесь никакого парадокса. Проблема в том, что у вас тесты не изолированы (а должны быть).

Один способ изолировать - это пересоздавать БД с нуля для каждого теста (об этом чуть ниже).

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

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

Ясно что это не для всего работает, так как все равно есть сущности, которые разделяемые, всякие словари и т.п.. Вот для тестирования именно работы с ними, нужно приводить БД в известное, стабильное состояние. Тут тоже есть варианты:

  1. пересоздавать БД
  2. не использовать комит (т.е. делать rollback транзакции).

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

Ну и еще одно замечание. Тестировать отдельные методы (типа тест на чтение, тест на удаление) - это обычно плохая затея. Нужно тестировать поведение. Это значит, что нужно тестировать не отдельно метод чтения, а поведение, т.е. суть теста должна быть - "после создания объект можно прочитать". В этом смысл создания, без чтения создание невозможно протестировать, точно так же как и нельзя (ну или в этом обычно нет смысла) без создания протестировать чтение. То же и с удалением. Метод удаления без чтения не протестировать и это не имеет смысла. Нужно тестировать "после удаления объект нельзя прочитать" (и соответственно до удаления должно быть можно). Поэтому создание, чтение и удаление имеет смысл тестировать в одном тесте.

→ Ссылка