Я использую SQL Server 2016 в качестве базы данных для производства и разработки (поэтому нет h2) с бэкэндом Spring Boot 2 и внешним интерфейсом Angular 7. Если я запускаю приложение нормально, все работает как положено. Для интеграционного тестирования (JUnit5) я бы хотел использовать Selenium, поэтому приложение должно фактически работать на порте и быть доступным через браузер. Мне также нужно подготовить некоторые данные перед каждым тестом (так как я не могу использовать производственные данные). Для достижения обоих целей я планировал использовать аннотацию @Sql
пружины , которая позволяет мне выполнять любой файл .sql
перед тестами (в моем случае я вставляю данные, которыми хотел бы манипулировать). Спринг откатывает все обратно после теста, поэтому должно хорошо работать. Однако при вставке данных запущенная тестом транзакция блокирует таблицы базы данных, а другие службы / репозитории, используемые приложением (например, для запроса данных), блокируются.
Пример. : Я вставляю сотрудника в файл, на который я ссылаюсь в аннотации @Sql
, затем Selenium запускает браузер и перехожу к списку сотрудников. На этом этапе список сотрудников не будет работать (который обслуживается с использованием конечной точки REST и EmployeeRepository
), поскольку он заблокирован транзакцией теста.
Я также могу подтвердить эту блокировку вручную, хотяпри выполнении тестов я не могу выполнить запросы с помощью SQL Server Management Studio (ожидание и завершение после завершения тестов).
Могу ли я использовать @Sql
или любой другой инструмент для подготовки данных для моих тестов и позволить приложению работатьнормально, а также возможность откатить изменения после тестов?
Тестовый класс:
@SpringBootTest(classes = ...App.class)
@ActiveProfiles(profiles = "test")
@ExtendWith(SpringExtension.class)
@Transactional
public class SeleniumExampleIT {
@LocalServerPort
protected int port;
protected WebDriver driver;
protected NgWebDriver ngWebDriver;
@BeforeAll
public static void setupClass() {
WebDriverManager.chromedriver().setup();
}
@BeforeEach
public void setupTest() {
var chromeDriver = new ChromeDriver();
driver = chromeDriver;
ngWebDriver = new NgWebDriver(chromeDriver);
ngWebDriver.waitForAngularRequestsToFinish();
}
@AfterEach
public void teardown() {
if (driver != null) {
driver.quit();
}
}
@Test
@Sql({"classpath:sql/test.sql"})
void listEmployeesTest() {
//...starting selenium
// navigating, waiting ..etc
}
}
EmployeeRepository
:
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Query("SELECT DISTINCT e FROM Employee e " +
"LEFT JOIN FETCH e.settings")
List<Employee> findAll();
@Query("SELECT DISTINCT e FROM Employee e " +
"LEFT JOIN FETCH e.settings " +
"WHERE e.id = :id")
Optional<Employee> findById(@Param("id") Long id);
}
Редактировать .:Аннотирование JpaRepository
методов с помощью @Transactional
не решило проблему (как уже упоминалось здесь ).
Edit2 .: Согласно Документам Spring
Если ваш тест равен @Transactional, он по умолчанию откатывает транзакцию в конце каждого метода тестирования. Однако, поскольку использование этого соглашения с RANDOM_PORT или DEFINED_PORT неявно обеспечивает реальную среду сервлета, HTTP-клиент и сервер работают в отдельных потоках и, следовательно, в отдельных транзакциях. Любая транзакция, инициированная на сервере, в этом случае не откатывается.