[SPRING] 전체 테스트를 트랜잭션없이 각 단위 테스트 후에 데이터베이스 상태를 어떻게 재설정합니까?
SPRING전체 테스트를 트랜잭션없이 각 단위 테스트 후에 데이터베이스 상태를 어떻게 재설정합니까?
저는 Spring 3.1.1.RELEASE, Hibernate 4.1.0.Final, JPA 2, JUnit 4.8.1 및 HSQL 2.2.7을 사용하고 있습니다. 내 서비스 메소드에서 몇 가지 JUnit 테스트를 실행하고 각 테스트 후에 메모리 내 데이터베이스에 기록 된 모든 데이터를 롤백하고 싶습니다. 그러나 전체 테스트가 트랜잭션으로 취급되기를 원하지는 않습니다. 예를 들어이 테스트에서
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class ContractServiceTest
{
…
@Autowired
private ContractService m_contractService;
@Test
public void testUpdateContract()
{
// Add the contract
m_contractService.save(m_contract);
Assert.assertNotNull(m_contract.getId());
// Update the activation date by 6 months.
final Calendar activationDate = Calendar.getInstance();
activationDate.setTime(activationDate.getTime());
activationDate.add(Calendar.MONTH, 6);
m_contract.setActivationDate(activationDate.getTime());
m_contractService.save(m_contract);
final List<Contract> foundContracts = m_contractService.findContractByOppId(m_contract.getOpportunityId());
Assert.assertEquals(foundContracts.get(0), m_contract);
} // testUpdateContract
서비스 ( "m_contractService.save", "m_contractService.save"및 "m_contractService.findContractByOppId")에 대한 세 가지 호출이 있으며 각각은 원하는 트랜잭션으로 처리됩니다. 그러나 각 단위 테스트 후에 메모리 데이터베이스를 원래 상태로 재설정하는 방법을 모르겠습니다.
추가 정보를 제공해야하는지 알려주세요.
해결법
-
==============================
1.당신이 최대 절전 모드를 사용하고 있기 때문에, hibernate.hbm2ddl.auto 프로퍼티를 사용하여 매번 시작할 때 데이터베이스를 생성 할 수있다. 또한 각 테스트 후에 스프링 컨텍스트를 강제로 다시로드해야합니다. @DirtiesContext 주석으로이를 수행 할 수 있습니다.
당신이 최대 절전 모드를 사용하고 있기 때문에, hibernate.hbm2ddl.auto 프로퍼티를 사용하여 매번 시작할 때 데이터베이스를 생성 할 수있다. 또한 각 테스트 후에 스프링 컨텍스트를 강제로 다시로드해야합니다. @DirtiesContext 주석으로이를 수행 할 수 있습니다.
이렇게하면 테스트에 약간의 오버 헤드가 추가 될 수 있으므로 다른 해결책은 각 테이블에서 수동으로 데이터를 삭제하는 것입니다.
-
==============================
2.@DirtiesContext는 나를위한 해결책이 아니 었습니다. 왜냐하면 전체 응용 프로그램 컨텍스트가 파괴되기 때문에 각 테스트 후에 만들어야하기 때문입니다.
@DirtiesContext는 나를위한 해결책이 아니 었습니다. 왜냐하면 전체 응용 프로그램 컨텍스트가 파괴되기 때문에 각 테스트 후에 만들어야하기 때문입니다.
@ 전에는 각 IntegrationTest에서 @Before를 만들어야하므로 나에게도 좋은 해결책이 아니 었습니다.
그래서 나는 각 테스트 후에 데이터베이스를 다시 만드는 TestExecutionListener를 만들기로 결정했습니다. (liquibase와 함께하지만, 그것은 또한 flyway 및 일반 SQL과 함께 작동)
public class CleanupDatabaseTestExecutionListener extends AbstractTestExecutionListener { public final int getOrder() { return 2001; } private boolean alreadyCleared = false; @Override public void prepareTestInstance(TestContext testContext) throws Exception { if (!alreadyCleared) { cleanupDatabase(testContext); alreadyCleared = true; } else { alreadyCleared = true; } } @Override public void afterTestClass(TestContext testContext) throws Exception { cleanupDatabase(testContext); } private void cleanupDatabase(TestContext testContext) throws LiquibaseException { ApplicationContext app = testContext.getApplicationContext(); SpringLiquibase springLiquibase = app.getBean(SpringLiquibase.class); springLiquibase.setDropFirst(true); springLiquibase.afterPropertiesSet(); //The database get recreated here } }
TestExecutionListenere를 사용하려면 사용자 정의 테스트 주석을 만들었습니다.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @RunWith(SpringRunner.class) @SpringBootTest(classes = OurderApp.class) @TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS, listeners = {CleanupDatabaseTestExecutionListener.class} ) public @interface OurderTest { }
마지막으로 테스트를 작성할 수 있으며 데이터베이스가 클린 모드인지 확인할 수 있습니다.
@RunWith(SpringRunner.class) @OurderTest public class ProductSaveServiceIntTest { }
편집 : 내 솔루션을 조금 향상되었습니다. 나는 언젠가 하나의 테스트 메소드가 테스트 클래스 내의 다가오는 모든 테스트에 대해 내 데이터베이스를 파괴했다는 문제점을 안고 있었다. 그래서 주석을 만들었습니다.
package com.ourder.e2e.utils;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ClearContext { }
이것을 CleanupDatabaseTestExectionListener에 추가했습니다.
@Override public void afterTestMethod(TestContext testContext) throws Exception { if(testContext.getTestMethod().getAnnotation(ClearContext.class)!=null){ cleanupDatabase(testContext); } super.afterTestMethod(testContext); }
이 두 조각의 도움으로 나는 이제 다음과 같은 테스트를 만들 수 있습니다.
@Test @ClearContext public void testWhichDirtiesDatabase() {}
-
==============================
3.org.springframework.transaction.annotation.Transactional의 Junit 클래스 레벨에서 @Transactional 어노테이션을 사용할 수있다.
org.springframework.transaction.annotation.Transactional의 Junit 클래스 레벨에서 @Transactional 어노테이션을 사용할 수있다.
예 :
package org.test import org.springframework.transaction.annotation.Transactional; @Transactional public class ArmyTest{ }
-
==============================
4.데이터베이스에서 모든 데이터를 삭제하는 @Before 메서드를 만듭니다. Hibernate를 사용하고 있으므로 HQL : Contract에서 delete를 사용할 수 있습니다.
데이터베이스에서 모든 데이터를 삭제하는 @Before 메서드를 만듭니다. Hibernate를 사용하고 있으므로 HQL : Contract에서 delete를 사용할 수 있습니다.
from https://stackoverflow.com/questions/14343893/how-do-i-reset-my-database-state-after-each-unit-test-without-making-the-whole-t by cc-by-sa and MIT license