2017-10-27 2 views
1

데이터베이스와 rabbitmq 사용법이있는 작은 스프링 부팅 응용 프로그램이 있습니다. 그래서 통합 테스트 (H2 + apache qpid)로 테스트하고 싶습니다.@SpringBootTest + @BeforeAll

@ExtendWith(SpringExtension.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = TestSpringConfig.class) 
@TestInstance(TestInstance.Lifecycle.PER_CLASS) 

내 응용 프로그램으로 시작 @BeforeAll를 사용하여 데이터베이스와 MQ 임 기대 :

@BeforeAll 
public void before() { 
    startMessageBroker(); 
    startDatabase(); 
} 

문제는 내 웹 응용 프로그램은 @BeforeAll에 정의 된 데이터베이스/MQ 전에 시작한다는 것입니다.

org.springframework.test.context.junit.jupiter.SpringExtension :

public class SpringExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor, 
     BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, 
     ParameterResolver { 
// ... 
    @Override 
    public void beforeAll(ExtensionContext context) throws Exception { 
     getTestContextManager(context).beforeTestClass(); 
    } 
// ... 
    @Override 
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { 
     getTestContextManager(context).prepareTestInstance(testInstance); 
    } 
// ... 

웹 응용 프로그램은 beforeAll에서 postProcessTestInstance 위상과 @BeforeAll 방법에서 시작됩니다.

org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor :

private void execute(TestDescriptor testDescriptor, C parentContext, ExecutionTracker tracker) { 
    Node<C> node = asNode(testDescriptor); 
    tracker.markExecuted(testDescriptor); 

    C preparedContext; 
    try { 
     preparedContext = node.prepare(parentContext); // 1 <<< 
     SkipResult skipResult = node.shouldBeSkipped(preparedContext); 
     if (skipResult.isSkipped()) { 
      this.listener.executionSkipped(testDescriptor, skipResult.getReason().orElse("<unknown>")); 
      return; 
     } 
    } 
    catch (Throwable throwable) { 
     rethrowIfBlacklisted(throwable); 
     // We call executionStarted first to comply with the contract of EngineExecutionListener 
     this.listener.executionStarted(testDescriptor); 
     this.listener.executionFinished(testDescriptor, TestExecutionResult.failed(throwable)); 
     return; 
    } 

    this.listener.executionStarted(testDescriptor); 

    TestExecutionResult result = singleTestExecutor.executeSafely(() -> { 
     C context = preparedContext; 
     try { 
      context = node.before(context); // 2 <<< 

      C contextForDynamicChildren = context; 
      context = node.execute(context, dynamicTestDescriptor -> { 
       this.listener.dynamicTestRegistered(dynamicTestDescriptor); 
       execute(dynamicTestDescriptor, contextForDynamicChildren, tracker); 
      }); 

      C contextForStaticChildren = context; 
      // @formatter:off 
      testDescriptor.getChildren().stream() 
        .filter(child -> !tracker.wasAlreadyExecuted(child)) 
        .forEach(child -> execute(child, contextForStaticChildren, tracker)); 
      // @formatter:on 
     } 
     finally { 
      node.after(context); 
     } 
    }); 

    this.listener.executionFinished(testDescriptor, result); 
} 

참조 점 1과 2는 '전에'다음 '준비'의 실행하고있다.

확실하지 않은 점은 junit, SpringExtension 또는 Im의 문제입니다. 어떤 조언이 필요합니까?

의 JUnit 목성 : 5.0.1

스프링 시험 : 5.0.0.RELEASE

스프링 부팅 테스트 : 1.5.8.RELEASE

+0

@BeforeAll 메서드는 정적 메서드 – Yogi

+0

이어야합니다. SpringExtension이 응용 프로그램 컨텍스트를 만들 때 의존하는 경우 Spring ['TestExecutionListener'] (https://docs.spring.io/spring/)을 구현하는 것이 좋습니다. docs/current/spring-framework-reference/testing.html # testcontext-tel-config). –

답변

0

의 JUnit 5 @BeforeAll] annotation은 JUnit 4의 @BeforeClass 주석 대체입니다. 주석 된 메소드가 현재 테스트 클래스의 모든 테스트 전에 실행되어야한다는 신호를 보내는 데 사용됩니다.

@BeforeAll는 더 많은 독서를 들어 정적 메소드

에 사용되어야한다 : 이것은 의도적으로 설계된 동작입니다

  1. http://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
+0

예, 그래야합니다. 좋은 지적. 빠르면 정적 또는 정적이 아닌 실행 흐름에 대한 차이점이 없습니다. @BeforeAll 메서드는 두 경우 모두에서 웹 응용 프로그램이 시작된 후에 실행됩니다. 또한 junit 소스에서 볼 수 있듯이 주석이 달린 메소드를 찾고 있습니다. 참조 : https://github.com/junit-team/junit5/blob/master/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java line 337. – Alex

0

, 나는 생각한다. Bean 포스트 프로세서/컨텍스트 이니셜 라이저를 init에 추가/DB/rabbitMQ를 시작하십시오.

0

테스트 클래스에서 DB 및 메시지 브로커를 시작해야하는 이유가 있습니까? 이것이 설계 상으로는 잘못된 것 같습니다. 인프라 스트럭처의 일부이므로 응용 프로그램 컨텍스트와 함께 시작해야합니다.

인프라를 설정하는 것은 테스트의 책임이 아닙니다.

IMHO, 일을 더 나은 방법은 다음과 같다 :

    + 응용 프로그램의 컨텍스트를 시작하는 때 H2를 시작하는 방식으로 선발을 구성 받는다는에 test 범위와
  • 사용 H2 의존성
  • 시작 아파치 qpid (휘젓고 포함) 응용 프로그램에 그냥 당신이 테스트 케이스
를 실행하기 전에 물건을 정리해야합니다 @Before에서
  • 시작
  • +0

    I 테스트 범위가있는 H2가 있어야합니다. 나는 임베디드로 Qpid 있습니다. 봄 부팅 전에 H2/Qpid를 시작하는 방법에 대한 제안이 있습니까? BeforeAll을 사용하기로되어 있지만이 경우는 작동하지 않는 것처럼 보입니다. 포스트 프로세서/컨텍스트 이벤트 사용은 ConnectionFactory가있는 Bean이 이미 초기화를 시작하기 때문에 불가능합니다. 저는 게으르지 만 노는 일이 없었습니다. 그래서 몇 가지 실제 사례가 있다면 나와 공유하십시오. – Alex

    +0

    흠 .. Configuration + Order를 사용해 볼 수 있습니다. – Alex

    +0

    그래, 가장 쉬운 방법은 @ 주문을 추가하는 것이고, 다른 방법은 선발을 사용하는 것입니다. qpid의 경우 https://github.com/tabish121/qpid-jms-spring-boot를 사용할 수 있습니다 (타사 라이브러리에 대한 제한이없는 경우). H2의 경우 여기 http://www.baeldung.com/spring-testing-separate-data-source에서 무엇인가를 사용할 수 있습니다. 먼저 콩이 항상 콩에서 시작하기 때문에 여기에서 원하는 것을 시작할 수 있습니다. –

    관련 문제