2011-08-22 4 views
2

내 JUnit 테스트에 @Transactional을 사용하고 있습니다 (주된 이점은 한 테스트 내에서 변경 사항을 롤백하는 것입니다.)하지만이 문제는 내 서비스 트랜잭션에 영향을 미칩니다. 그래서 예를 들면이다서비스 트랜잭션에서의 스프링 테스트

내 서비스 :

@Service 
@Transactional(propagation = Propagation.REQUIRED) 
public class ServiceImpl 

내 단위 테스트 : 나는 두 개의 별도의 service.add (대한 거래)하지만 사용하지 않는 한이 예상 그래서 순진

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "/test-context.xml" }) 
@Transactional 
public class TestService 

@Test 
public void testNumberTransaction() { 
Entity a = new Entity(); 
Entity b = new Entity(); 
service.add(a); 
service.add(b); 
} 

@ nontransactional 테스트 메소드에서 하나의 트랜잭션 내에서 실행됩니다 (하지만 테스트 후 롤백하지 않음).

예상 되나요? 일부 구성으로 변경할 수 있습니까?

감사합니다.

답변

4

예, 예상됩니다. Propagation.REQUIRED (기본값)은 다음을의 L합니다. 존재하는 경우 기존 트랜잭션에서 실행하십시오. 그렇지 않으면, 트랜잭션을 생성하고 메소드가 끝날 때 커밋하십시오.

그렇습니다. 전체 테스트 메소드가 트랜잭션 인 경우 두 서비스 호출이 테스트 트랜잭션의 컨텍스트에서 실행됩니다.

서비스에는 REQUIRED이라는 주석이 붙어 있으므로 트랜잭션이 이미 존재하는 경우 작동한다고 가정합니다. 이 테스트는 유효합니다. 기존 트랜잭션의 컨텍스트에서 서비스를 테스트합니다. 서비스를 전용 트랜잭션으로 실행하려면 REQUIRES_NEW 주석을 사용해야합니다. 물론 그럴 경우 트랜잭션에서 테스트를 실행하여 서비스 트랜잭션을 롤백 할 수 없습니다.

2

기본적으로 (REQUIRES은 기본 전파 동작입니다.) 트랜잭션이 이미 존재하는 경우 서비스 메소드는 새로운 메소드를 생성하지 않고 존재하는 메소드에 조인합니다. 귀하의 경우 Spring 테스트 프레임 워크 (롤백 될 트랜잭션)에 의해 생성 된 트랜잭션입니다.

전파를 REQUIRES_NEW으로 설정하여이 동작을 변경할 수 있습니다. 그러나 이제는 비즈니스 add 메서드가 새 트랜잭션 내에서 실행되기 때문에 일단이 메서드를 종료하면 트랜잭션은 롤백되지 않고 커밋됩니다. 기본적으로 모든 트랜잭션은 JUnit 테스트 트랜잭션에서 조인되므로 데이터베이스에 대한 모든 변경 사항은 롤백됩니다.

1

@Transactional은 경계선을 정의합니다. 클래스에 주석을다는 것은 클래스의 각 public 메소드에 주석을다는 것과 같습니다. 구분선은 여전히 ​​메소드입니다 (경우에 따라 testNumberTransaction()). 커밋/롤백 결정은 경계 지점에서, 즉 테스트 방법에서 돌아올 때 취해집니다. REQUIRES 또는 REQUIRES_NEW 전달 여부에 관계없이 실제 거래 단위는 동일하므로 testNumberTransaction() 메서드이므로 두 개의 service.add(...) 호출은 항상 동일한 트랜잭션에서 실행됩니다.

테스트 후 트랜잭션을 항상 롤백하려는 경우 @Transactional 주석을 제거하거나 언급 한대로 @nontransactional을 제거하면됩니다.

다른 한편으로는, 각 service.add(...) 호출에 대해 새로운 트랜잭션을 강제하려는 경우, 당신은 당신이 @Transactional (전파 = 전파로 주석하는 add(...) 방법이 당신의 서비스 클래스에 대한 래퍼를 만들 수 중 하나. REQUIRES_NEW)을 호출 한 다음 랩핑 된 service 인스턴스 add(...) 메소드를 호출하십시오. 또는 스프링 테스트 컨텍스트에서 일부 선언적 트랜잭션 관리를 추가하여 service.add(...) 메소드에 대한 트랜잭션 조언을 추가 할 수 있습니다. <tx:XXX> 태그를 사용하여 선언적 트랜잭션 지원을 추가하는 방법에 대한 자세한 내용은 spring documentation을 참조하십시오.

+1

테스트 메소드에서 @Transactional을 제거해도 트랜잭션이 롤백되지 않으므로 테스트 트랜잭션이 없습니다. 트랜잭션은 서비스 메소드가 호출 될 때 시작될 것이고, 서비스 메소드가 리턴 할 때 커밋 할 것이다. –

+0

내 진실하고 어색한 배합. @Transactional 어노테이션을 제거하면 트랜잭션 관리자가 Java 계층에서 트랜잭션을 생성하지 못하게됩니다. 그러나 대부분의 데이터베이스는 각 세션에 대해 항상 암시 적 트랜잭션을 생성하며 자동 커밋을 해제 (기본값 : IIRC)하면 트랜잭션은 항상 롤백되는 트랜잭션과 동일한 방식으로 작동하지 않습니다. 내가 틀렸다면 나를 바로 잡아주세요. – pap

+0

Err, no. * test * 메소드에서 Transactional을 제거하면 테스트는 트랜잭션 컨텍스트 외부에서 실행되지만 * service * 메소드는 Transactional로 주석 처리되므로 Spring은 각 서비스 메소드 호출에 대한 트랜잭션을 계속 시작합니다. 서비스 자체가 런타임 예외를 throw하지 않는 한 서비스에서 수행 된 실제 트랜잭션 작업 (일부 데이터베이스를 업데이트 할 수 있음)은 트랜잭션에서 완료되고 커밋됩니다. –