2013-06-15 4 views
1

내가 (생산) 일부 코드가 있습니다LazyInitializationExceptions를 테스트하는 방법은 무엇입니까?

  • 은 하나 개의 스레드에서 DB를 다른 스레드에서
  • 의 데이터를 캐시를, 소수, 캐시에서 데이터를 잡고하며 속성의 반복이 시작됩니다.

이 내용은 LazyInitializationException입니다.

문제를 해결하는 방법을 알고 있지만이 문제를 해결하기 위해 테스트를 받고 싶습니다. 그러나 나는 테스트의 올바른 부분에서 예외를 재현하는 방법을 알아낼 수 없습니다.

일부 테스트 데이터로 DB를 초기화해야하므로 내 테스트에 @Transactional으로 주석이 첨부됩니다. 그렇게하지 않으면 설정이 실패합니다 ... 당신은 그것을 짐작했습니다 ... LazyInitializationException.

@Transactional 
public class UpdateCachedMarketPricingActionTest extends AbstractIntegrationTest { 

    @Autowired 
    private UpdateCachedMarketPricingAction action; 

    @Autowired 
    private PopulateMarketCachesTask populateMarketCachesTask; 

    @Test @SneakyThrows 
    public void updatesCachedValues() 
    { 

     // Populate the cache from a different thread, as this is how it happens in real life 
     Thread updater = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       populateMarketCachesTask.populateCaches(); 
      } 
     }); 
     updater.start(); 
     updater.join(); 

      updateMessage = {...} //ommitted 

     action.processInstrumentUpdate(updateMessage); 
    } 

그래서, 나는 현재 @Transaction 범위 밖에서 그것을 얻을려고, 별도의 스레드에서 내 캐시를 못쓰게 해요 :

여기에 내 현재 테스트입니다. 또한 캐시 프라이머 내부에 entityManager.detatch(entity)을 호출하여 캐시 내에있는 엔티티가 해당 콜렉션을 지연로드 할 수 없도록하려고 시도합니다.

그러나 테스트에 통과해도 예외는 발생하지 않습니다.

엔티티를 다음 번에 컬렉션을 반복 할 때 강제로 가져올 수있는 경우 엔 LazyInitializationException이 발생합니까?

+0

그 어떤 부분을 조롱 할 수 없습니까? 재현하기가 훨씬 쉬울 것입니다. – fge

+0

사실 ... 테스트의 목적에 어긋납니다. 생산 현장에서 발생하는 버그를 방지하기 위해 이러한 움직이는 부분의 특정 동작을 테스트하려고합니다. 핵심 요소를 조롱하면 테스트를 더 쉽게 작성할 수 있지만 무의미합니다. –

+0

솔직히, 나는 왜 보이지 않는가? 당신은 mockito를 사용하여 (적어도 mockito를 사용하여)'mock.next(). thenReturn() .Return(). ThenThrow()'를 할 수 있다는 것을 알고 있습니까?그리고'when()'의 결과를 얻는다면'.thenThrow()'전에 임의의 수의'.thenReturn()'을 연결할 수 있습니다. 나는 양립하지 않는다. 잠을 에뮬레이트 할 수 있습니다! – fge

답변

0

각 조작의 트랜잭션이 서로 독립적으로 확약되어야합니다. 테스트 메소드 또는 테스트 클래스에 @Tranactional으로 주석을 붙이면 현재 테스트 트랜잭션을 연 상태로두고 전체 테스트 실행 후 다시 롤백합니다.

@Autowired 
private PlatformTransactionManager transactionManager; 


@Test 
public void example() { 
    new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() { 

     @Override 
     protected void doInTransactionWithoutResult(TransactionStatus status) { 
      // add your code here... 
     } 
    }); 
} 

당신은 자신의 콜백에서 첫 번째 조작을 호출 한 다음 다른 콜백에서 두 번째 작업을 호출 할 수있다 :

그래서 하나의 옵션은 다음과 같은 일을 할 것입니다. 그런 다음 콜백 후에 Hibernate 또는 JPA 엔티티에 액세스 할 때 엔티티는 더 이상 현재 작업 단위 (예 : 최대 절전 모드 Session)에 연결되지 않습니다. 결과적으로 해당 지점에서 지연 컬렉션 또는 필드에 액세스하면 LazyInitializationException이됩니다.

감사합니다,

추신 이 기술은 자연스럽게 데이터베이스에 적용된 변경 사항을 남겨 둡니다. 따라서 수정 된 상태를 정리해야하는 경우 @AfterTransaction 메소드에서 수동으로 수정하는 것이 좋습니다.

관련 문제