1. 소개

Spring은 통합 테스트 뿐만 아니라 애플리케이션 코드 전체에서 선언적 트랜잭션 관리를 훌륭하게 지원합니다 .

그러나 경우에 따라 트랜잭션 경계에 대한 세밀한 제어가 필요할 수 있습니다.

이 기사에서는 트랜잭션 테스트에서 Spring이 설정한 자동 트랜잭션과 프로그래밍 방식으로 상호 작용하는 방법을 살펴봅니다 .

2. 전제 조건

Spring 애플리케이션에 몇 가지 통합 테스트가 있다고 가정해 봅시다.

특히 데이터베이스와 상호 작용하는 테스트를 고려하고 있습니다. 예를 들어 지속성 계층이 올바르게 작동하는지 확인합니다.

트랜잭션으로 어노테이션이 달린 표준 테스트 클래스를 고려해 보겠습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { HibernateConf.class })
@Transactional
public class HibernateBootstrapIntegrationTest { ... }

이러한 테스트에서 모든 테스트 메서드는 메서드가 종료될 때 롤백되는 트랜잭션에 래핑됩니다 .

물론 특정 메서드에만 어노테이션을 추가하는 것도 가능합니다. 이 문서에서 논의할 모든 내용은 해당 시나리오에도 적용됩니다.

3. TestTransaction 클래스

우리는 기사의 나머지 부분을 단일 클래스인 org.springframework.test.context.transaction.TestTransaction 에 대해 설명할 것 입니다.

이것은 테스트에서 트랜잭션과 상호 작용하는 데 사용할 수 있는 몇 가지 정적 메서드가 있는 유틸리티 클래스입니다.

각 메서드는 테스트 메서드 실행 중에 있는 유일한 현재 트랜잭션과 상호 작용합니다.

3.1. 현재 트랜잭션 상태 확인

우리가 테스트에서 자주 하는 한 가지는 사물이 있어야 할 상태에 있는지 확인하는 것입니다.

따라서 현재 활성 트랜잭션이 있는지 확인해야 할 수 있습니다.

assertTrue(TestTransaction.isActive());

또는 현재 트랜잭션이 롤백 플래그가 지정되었는지 여부를 확인하는 데 관심이 있을 수 있습니다.

assertTrue(TestTransaction.isFlaggedForRollback());

그렇다면 Spring은 자동으로 또는 프로그래밍 방식으로 종료 직전에 롤백합니다. 그렇지 않으면 닫기 직전에 커밋됩니다.

3.2. 커밋 또는 롤백을 위해 트랜잭션에 플래그 지정

트랜잭션을 닫기 전에 트랜잭션을 커밋하거나 롤백하도록 정책을 프로그래밍 방식으로 변경할 수 있습니다.

TestTransaction.flagForCommit();
TestTransaction.flagForRollback();

일반적으로 테스트의 트랜잭션은 시작할 때 롤백 플래그가 지정됩니다. 그러나 메서드에 @Commit 어노테이션이 있는 경우 대신 커밋 플래그가 지정되기 시작합니다.

@Test
@Commit
public void testFlagForCommit() {
    assertFalse(TestTransaction.isFlaggedForRollback());
}

이러한 메서드는 이름에서 알 수 있듯이 단순히 트랜잭션에 플래그를 지정합니다. 즉, 트랜잭션이 즉시 커밋되거나 롤백되지 않고 종료 직전에만 수행됩니다.

3.3. 트랜잭션 시작 및 종료

트랜잭션을 커밋하거나 롤백하려면 메서드를 종료하거나 명시적으로 종료합니다.

TestTransaction.end();

나중에 데이터베이스와 다시 상호 작용하려면 새 트랜잭션을 시작해야 합니다.

TestTransaction.start();

새 트랜잭션은 메서드의 기본값에 따라 롤백(또는 커밋) 플래그가 지정됩니다. 즉, flagFor… 에 대한 이전 호출 은 새 트랜잭션에 아무런 영향을 미치지 않습니다.

4. 일부 구현 세부 정보

TestTransaction 은 마법 같은 것이 아닙니다. 이제 Spring을 사용한 테스트에서 트랜잭션에 대해 조금 더 배우기 위해 구현을 살펴보겠습니다.

몇 가지 메서드가 현재 트랜잭션에 액세스하고 일부 기능을 캡슐화하는 것을 볼 수 있습니다.

4.1. TestTransaction 은 현재 트랜잭션 을 어디에서 가져옵니까?

코드로 바로 이동해 보겠습니다.

TransactionContext transactionContext
  = TransactionContextHolder.getCurrentTransactionContext();

TransactionContextHolder 는 TransactionContext 를 보유 하는 ThreadLocal 주변의 정적 래퍼 입니다.

4.2. 누가 스레드 로컬 컨텍스트를 설정합니까?

누가 setCurrentTransactionContext 메서드 를 호출하는지 살펴보면 호출자는 TransactionalTestExecutionListener.beforeTestMethod 한 명뿐입니다 .

TransactionalTestExecutionListener 는 @Transactional 어노테이션이 달린 테스트에서 Springs가 자동으로 구성하는 리스너입니다 .

TransactionContext실제 트랜잭션에 대한 참조를 보유하지 않습니다. 대신 PlatformTransactionManager 에 대한 외관일 뿐입니다 .

예, 이 코드는 계층이 많고 추상적입니다. 이는 종종 Spring 프레임워크의 핵심 부분입니다.

복잡성 하에서 Spring이 흑마술을 수행하지 않고 많은 필요한 부기, 배관, 예외 처리 등을 수행하는 방법을 보는 것은 흥미 롭습니다.

5. 결론

이 빠른 사용방법(예제)에서는 Spring 기반 테스트에서 트랜잭션과 프로그래밍 방식으로 상호 작용하는 방법을 살펴보았습니다.

이 모든 예제의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다. 이것은 Maven 프로젝트이므로 그대로 가져오고 실행하기 쉬워야 합니다.

Persistence footer banner