봄의 각 테스트 전에 데이터베이스를 재생성하려면 어떻게 해야 합니까?
의 데이터베이스 설정은 Spring-Boot-Mvc-Web으로 .application.properties
삭제:
spring.datasource.url=jdbc:h2:tcp://localhost/~/pdk
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
이게 내가 만든 유일한 설정이야내가 만든 다른 구성은 어디에도 없어.그러나 스프링 및 하위 시스템은 각 웹 응용 프로그램이 실행될 때마다 자동으로 데이터베이스를 다시 작성합니다.데이터베이스는 응용 프로그램 종료 후 데이터를 포함하는 동안 시스템 실행 시 다시 생성됩니다.
이 디폴트를 이해하지 못했기 때문에 테스트에 적합하다고 생각하고 있었습니다.
그러나 테스트를 시작했을 때 데이터베이스가 한 번만 다시 작성된다는 것을 알게 되었습니다.테스트는 사전 정의된 순서에 따라 수행되기 때문에 이는 전혀 의미가 없습니다.
그래서 질문은, 어떻게 말이 되는가? 즉, 애플리케이션을 처음 시작할 때처럼 각 테스트 전에 데이터베이스를 재생성하려면 어떻게 해야 합니까?
테스트 클래스 헤더는 다음과 같습니다.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = myapp.class)
//@WebAppConfiguration
@WebIntegrationTest
@DirtiesContext
public class WebControllersTest {
하다, 하다@DirtiesContext
전혀 도움이 안 됐어요
갱신하다
나는 콩이 있다.
@Service
public class DatabaseService implements InitializingBean {
방법이 있다.
@Override
@Transactional()
public void afterPropertiesSet() throws Exception {
log.info("Bootstrapping data...");
User user = createRootUser();
if(populateDemo) {
populateDemos();
}
log.info("...Bootstrapping completed");
}
이렇게 .populateDemos()
데이터베이스에서 모든 데이터를 지우는 방법을 지정합니다.시험 에는 호출하지 .@DirtiesContext
사실, 내 생각엔 네가 이걸 원하는 것 같아.
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
@DirtiesContext는 동일한 클래스 내에서 클래스 수준 및 메서드 수준 주석으로 사용할 수 있습니다.이러한 시나리오에서 Application Context는 이러한 주석이 달린 메서드 후와 클래스 전체 후에 더티로 표시됩니다.Dirties Context의 경우.ClassMode는 AFTER_EACH_TEST_METHOD로 설정되어 있습니다.클래스의 각 테스트 메서드 후에 컨텍스트는 더티 마크가 붙습니다.
시험 수업 시간에 붙여놨잖아
Spring-Boot 2.2.0에서 승인된 답변을 사용하면 제약조건과 관련된 JDBC 구문 오류가 나타납니다.
원인: org.h2.jdbc.JdbcSQLSyntaxErrorException:제약사항 "FKEFFD698EA2E75FXEERWBO8"IOT"가 이미 있습니다. SQL 문: alter table foo add restraint FKeffd698ea2e75fxeerwbo8iut 외래 키 참조 바 [90045-200]
저는 이 부분을 .@AutoConfigureTestDatabase
"spring-boot-test-autoconfigure" (스프링 부트 테스트 자동 구성):
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
@AutoConfigureTestDatabase(replace = Replace.ANY)
public class FooRepositoryTest { ... }
는 다른 '아주 좋다'를 .spring.jpa.hibernate.ddl-auto=create-drop
은 매우
@Transactional(value=JpaConfiguration.TRANSACTION_MANAGER_NAME)
@Sql(executionPhase=ExecutionPhase.BEFORE_TEST_METHOD,scripts="classpath:/test-sql/group2.sql")
public class GroupServiceTest extends TimeoffApplicationTests {
되어 있습니다.org.springframework.test.context.jdbc.Sql;
사전 테스트 방법과 사후 테스트 방법을 실행할 수 있습니다.데이터베이스를 채웁니다.
매번 데이터베이스 작성과 관련하여, "테스트에서 이 주석을 사용하여 사용자 지정 속성을 사용하여 테스트를 구성할 수 있는 create-drop 옵션만 갖기를 원합니다."
@TestPropertySource(locations="classpath:application-test.properties")
public class TimeoffApplicationTests extends AbstractTransactionalJUnit4SpringContextTests{
도움이 되었으면 좋겠다
을 @DirtiesContext
, 아래의 코드가 도움이 됩니다.나는 이 대답에서 몇 가지 코드를 사용했다.
H2 를 H2로 합니다.application.yml
다음 파일을 테스트 리소스 폴더에 저장합니다.
spring:
datasource:
platform: h2
url: jdbc:h2:mem:test
driver-class-name: org.h2.Driver
username: sa
password:
후에 '아,아,아,아'라는를 만듭니다.ResetDatabaseTestExecutionListener
:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
public class ResetDatabaseTestExecutionListener extends AbstractTestExecutionListener {
@Autowired
private DataSource dataSource;
public final int getOrder() {
return 2001;
}
private boolean alreadyCleared = false;
@Override
public void beforeTestClass(TestContext testContext) {
testContext.getApplicationContext()
.getAutowireCapableBeanFactory()
.autowireBean(this);
}
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
if (!alreadyCleared) {
cleanupDatabase();
alreadyCleared = true;
}
}
@Override
public void afterTestClass(TestContext testContext) throws Exception {
cleanupDatabase();
}
private void cleanupDatabase() throws SQLException {
Connection c = dataSource.getConnection();
Statement s = c.createStatement();
// Disable FK
s.execute("SET REFERENTIAL_INTEGRITY FALSE");
// Find all tables and truncate them
Set<String> tables = new HashSet<>();
ResultSet rs = s.executeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='PUBLIC'");
while (rs.next()) {
tables.add(rs.getString(1));
}
rs.close();
for (String table : tables) {
s.executeUpdate("TRUNCATE TABLE " + table);
}
// Idem for sequences
Set<String> sequences = new HashSet<>();
rs = s.executeQuery("SELECT SEQUENCE_NAME FROM INFORMATION_SCHEMA.SEQUENCES WHERE SEQUENCE_SCHEMA='PUBLIC'");
while (rs.next()) {
sequences.add(rs.getString(1));
}
rs.close();
for (String seq : sequences) {
s.executeUpdate("ALTER SEQUENCE " + seq + " RESTART WITH 1");
}
// Enable FK
s.execute("SET REFERENTIAL_INTEGRITY TRUE");
s.close();
c.close();
}
}
위의 코드는 데이터베이스(테이블 트리네이트, 시퀀스 리셋 등)를 리셋하고 H2 데이터베이스와 연동할 수 있도록 준비합니다.다른 메모리 데이터베이스(HsQLDB 등)를 사용하는 경우 동일한 작업을 수행하려면 SQL 쿼리에서 필요한 변경을 수행해야 합니다.
후 하여 '어느 정도'를 추가합니다.@TestExecutionListeners
★★★★
@TestExecutionListeners(mergeMode =
TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
listeners = {ResetDatabaseTestExecutionListener.class}
)
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CreateOrderIT {
이거면 될 거야.
@DirtiesContext
를 사용하고 있을 가능성이 있습니다.@MockBean
테스트에서는 스프링 콘텍스트를 더티로 마크하고 콘텍스트 전체를 자동으로 새로고침합니다.
스프링 부트에서는 각 테스트에 대해 h2 데이터베이스를 일의로 정의할 수 있습니다.각 테스트의 데이터 소스 URL을 덮어씁니다.
@SpringBootTest(properties = {"spring.config.name=myapp-test-h2","myapp.trx.datasource.url=jdbc:h2:mem:trxServiceStatus"})
테스트는 병렬로 실행할 수 있습니다.
테스트 중 데이터는 다음과 같이 재설정할 수 있습니다.
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
JUnit 5 테스트의 "H2 데이터베이스 리셋" 기능을 다루는 라이브러리가 있습니다.
https://github.com/cronn/test-utils#h2util
사용 예:
@ExtendWith(SpringExtension.class)
@Import(H2Util.class)
class MyTest {
@BeforeEach
void resetDatabase(@Autowired H2Util h2Util) {
h2Util.resetDatabase();
}
// tests...
}
메이븐 좌표:
<dependency>
<groupId>de.cronn</groupId>
<artifactId>test-utils</artifactId>
<version>0.2.0</version>
<scope>test</scope>
</dependency>
면책사항:저는 추천 도서관의 저자입니다.
「 」를 사용하고 spring.jpa.hibernate.ddl-auto=create-drop
데이터베이스를 작성/폐기하기에 충분한가?
Spring-Data 통합(전혀 모르는 것)을 사용하고 있지 않는 한, 이것은 커스텀 로직으로서 실장이 필요한 것 같습니다.Spring은 데이터베이스, 스키마 및 테이블에 대해 알지 못합니다.
가정하고 JUnit을 .@Before
★★★★★★★★★★★★★★★★★」@After
데이터베이스, 테이블 및 데이터를 설정하고 정리하는 방법.테스트 자체에서 필요한 데이터를 쓸 수 있으며, 필요에 따라 스스로 정리할 수도 있습니다.
시도/리소스를 사용하는 솔루션과 이 답변을 기반으로 구성 가능한 스키마를 사용합니다.문제는 H2 데이터베이스가 테스트 케이스 간에 데이터를 유출했다는 것입니다.그래서 이게Listener
는 각 테스트 방식보다 먼저 기동합니다.
그Listener
:
public class ResetDatabaseTestExecutionListener extends AbstractTestExecutionListener {
private static final List<String> IGNORED_TABLES = List.of(
"TABLE_A",
"TABLE_B"
);
private static final String SQL_DISABLE_REFERENTIAL_INTEGRITY = "SET REFERENTIAL_INTEGRITY FALSE";
private static final String SQL_ENABLE_REFERENTIAL_INTEGRITY = "SET REFERENTIAL_INTEGRITY TRUE";
private static final String SQL_FIND_TABLE_NAMES = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='%s'";
private static final String SQL_TRUNCATE_TABLE = "TRUNCATE TABLE %s.%s";
private static final String SQL_FIND_SEQUENCE_NAMES = "SELECT SEQUENCE_NAME FROM INFORMATION_SCHEMA.SEQUENCES WHERE SEQUENCE_SCHEMA='%s'";
private static final String SQL_RESTART_SEQUENCE = "ALTER SEQUENCE %s.%s RESTART WITH 1";
@Autowired
private DataSource dataSource;
@Value("${schema.property}")
private String schema;
@Override
public void beforeTestClass(TestContext testContext) {
testContext.getApplicationContext()
.getAutowireCapableBeanFactory()
.autowireBean(this);
}
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
cleanupDatabase();
}
private void cleanupDatabase() throws SQLException {
try (
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()
) {
statement.execute(SQL_DISABLE_REFERENTIAL_INTEGRITY);
Set<String> tables = new HashSet<>();
try (ResultSet resultSet = statement.executeQuery(String.format(SQL_FIND_TABLE_NAMES, schema))) {
while (resultSet.next()) {
tables.add(resultSet.getString(1));
}
}
for (String table : tables) {
if (!IGNORED_TABLES.contains(table)) {
statement.executeUpdate(String.format(SQL_TRUNCATE_TABLE, schema, table));
}
}
Set<String> sequences = new HashSet<>();
try (ResultSet resultSet = statement.executeQuery(String.format(SQL_FIND_SEQUENCE_NAMES, schema))) {
while (resultSet.next()) {
sequences.add(resultSet.getString(1));
}
}
for (String sequence : sequences) {
statement.executeUpdate(String.format(SQL_RESTART_SEQUENCE, schema, sequence));
}
statement.execute(SQL_ENABLE_REFERENTIAL_INTEGRITY);
}
}
}
사용자 지정 주석 사용:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestExecutionListeners(mergeMode =
TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
listeners = { ResetDatabaseTestExecutionListener.class }
)
public @interface ResetDatabase {
}
데이터베이스를 리셋하는 각 테스트를 쉽게 표시할 수 있습니다.
@SpringBootTest(
webEnvironment = RANDOM_PORT,
classes = { Application.class }
)
@ResetDatabase
public class SomeClassIT {
테스트 클래스에 주석을 달 수 있습니다.@Transactional
:
import org.springframework.transaction.annotation.Transactional;
...
...
@RunWith(SpringRunner.class)
@Transactional
public class MyClassTest {
@Autowired
private SomeRepository repository;
@Before
public void init() {
// add some test data, that data would be rolled back, and recreated for each separate test
repository.save(...);
}
@Test
public void testSomething() {
// add some more data
repository.save(...);
// update some base data
repository.delete(...);
// all the changes on database done in that test would be rolled back after test finish
}
}
모든 테스트는 트랜잭션에 포함되며 트랜잭션은 각 테스트가 끝날 때 롤백됩니다.물론 이 주석에는 몇 가지 문제가 있습니다. 예를 들어 프로덕션 코드에서 점수가 다른 트랜잭션을 사용하는 경우 각별히 주의해야 합니다.
컨테이너 내에서 데이터베이스를 실행하는 데 도움이 되는 https://www.testcontainers.org/을 시험해 볼 수도 있고 각 테스트 실행에 대해 새로운 데이터베이스를 작성할 수도 있습니다.그러나 컨테이너를 만들고 데이터베이스 서버를 시작, 구성 및 마이그레이션 작업을 수행해야 하므로 테스트 실행이 매우 느립니다.
아무것도 안 먹혔어.모든 테스트 클래스에 대해 다음 주석을 추가할 수 있습니다.
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) //in case you need tests to be in specific order
@DataJpaTest // will disable full auto-configuration and instead apply only configuration relevant to JPA tests
@AutoConfigureTestDatabase(replace = NONE) //configures a test database to use instead of the application-defined or auto-configured DataSource
클래스 내에서 특정 테스트를 주문하려면 @Order 주석도 추가해야 합니다.
@Test
@Order(1) //first test
@Test
@Order(2) //second test, etc.
이전에 db를 조작했기 때문에 테스트를 다시 실행해도 실패하지 않습니다.
언급URL : https://stackoverflow.com/questions/34617152/how-to-re-create-database-before-each-test-in-spring
'sourcecode' 카테고리의 다른 글
오류가 발생하는 이유: "Query" 유형의 필드 xx를 쿼리할 수 없습니까? (0) | 2023.03.25 |
---|---|
연락처 양식 7의 양식 액션 URL을 변경하는 방법 (0) | 2023.03.25 |
Rails에서 모든 컨트롤러 파라미터를 camelCase에서 snake_case로 변환하는 가장 좋은 방법은 무엇입니까? (0) | 2023.03.25 |
폼 7에 문의하면 HTTP 500 에러가 발생합니다. (0) | 2023.03.25 |
Spring RestTemplate에서의 SSL 증명서 검증 디세블화 (0) | 2023.03.25 |