2017-10-27 4 views
1

Ich habe eine kleine Spring Boot App mit Datenbank und Rabbitmq verwendet. Also würde ich gerne mit Integrationstest (H2 + Apache qpid) testen.@SpringBootTest + @BeforeAll

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

Da meine App erwarten Datenbank und mq Im @BeforeAll ihn zu benutzen:

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

Das Problem ist, dass meine Web-app beginnt, bevor Datenbank/mq in @BeforeAll definiert.

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); 
    } 
// ... 

Web App startet in postProcessTestInstance Phase und @BeforeAll Methoden in 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); 
} 

Siehe Punkte 1 und 2. Es gibt Ausführungen von 'vorbereiten' und dann 'vor'.

Ich bin mir nicht sicher ist es Problem von Junit, SpringExtension oder ich mache etwas falsch. Irgendwelche Ratschläge?

junit-jupiter: 5.0.1

Federtest: 5.0.0.RELEASE

Feder-boot-Test: 1.5.8.RELEASE

+0

Ihre Methode mit @BeforeAll sollte statische Methode sein – Yogi

+0

Wenn Sie davon abhängen, wann SpringExtension den Anwendungskontext erstellt, können Sie besser Spring ['TestExecutionListener'] implementieren (https://docs.spring.io/spring/ docs/current/Spring-Framework-Referenz/testing.html # testcontext-tel-config). –

Antwort

0

JUnit 5 [ @BeforeAll] Annotation ist der Ersatz von @BeforeClass Annotation in JUnit 4. Es wird verwendet, um zu signalisieren, dass die annotierte Methode vor allen Tests in der aktuellen Testklasse ausgeführt werden sollte.

@BeforeAll sollte in statischen Methode

für mehr Lesen verwendet werden:

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

Ja, sollte es sein. Guter Punkt. In Fast gibt es keine Unterschiede für den Ausführungsfluss mit statischen oder ohne statische Methode: Die Methode @BeforeAll wird ausgeführt, nachdem die Webanwendung in beiden Fällen gestartet wurde. Wie ich aus den Quellen von junit sehen kann, suchen sie nur nach annotierten Methoden. Siehe: https://github.com/junit-team/junit5/blob/master/junit-platform-commons/src/main/java/org/junit/platform/commons/util/AnnotationUtils.java Zeile 337. – Alex

0

Das ist von Entwurf, denke ich. Versuchen Sie, den Bean-Postprozessor/Kontextinitialisierer hinzuzufügen, um Ihren DB/rabbitMQ zu initialisieren/zu starten.

0

Gibt es einen Grund, die DB und den Nachrichtenbroker in der Testklasse zu starten? Es scheint mir, dass dies vom Design her falsch ist. Sie sollten beide zusammen mit Ihrem Anwendungskontext gestartet werden, da sie Teil Ihrer Infrastruktur sind.

Es ist keine Verantwortung Ihrer Tests, Ihre Infrastruktur einzurichten!

IMHO, ein besserer Weg, Dinge zu tun, ist die folgende:

  • Verwendung H2 Abhängigkeit mit einem test Umfang in Maven + einen Starter in einer Art und Weise konfigurieren H2 beginnt, wenn der Anwendungskontext Starten
  • starten apache qpid (prefferably embedded) auf Anfrage
  • In @Before starten nur sicherstellen, dass Sie Sachen aufzuräumen, bevor ein Testfall ausgeführt
+0

I habe H2 mit Testumfang. Ich habe Qpid als eingebettet. Irgendwelche Vorschläge, wie man H2/Qpid startet, bevor der Springboot startet? Ich sollte BeforeAll dafür verwenden, aber sieht so aus, als würde dieser Fall nicht funktionieren. Verwenden Sie das Postprozessor-/Kontextereignis nicht, da Bean mit ConnectionFactory die Initialisierung bereits startet. Ich habe versucht mit Lazy zu spielen, aber ohne Glück. Also, wenn du ein echtes Beispiel hast - bitte teile es mit mir. – Alex

+0

Hm .. Ich kann versuchen, Konfiguration + Bestellung .. – Alex

+0

Ja, der einfachste Weg wäre @Order hinzufügen, ist eine andere Möglichkeit, Starter zu verwenden. Für qpid können Sie https://github.com/tabish121/qpid-jms-spring-boot verwenden (wenn Sie keine Einschränkungen für Bibliotheken von Drittanbietern haben). Für H2 könnte man etwas von hier http://www.baeldung.com/spring-testing-separate-data-source verwenden. Die Sache ist, dass Starter immer vor deinen Bohnen beginnen, was du hier willst. –

Verwandte Themen