/* * Copyright 2015-2017 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html */ package org.junit.jupiter.engine.extension; import static java.util.Arrays.asList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.TestExtensionContext; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.jupiter.engine.JupiterTestEngine; import org.junit.platform.engine.test.event.ExecutionEventRecorder; import org.junit.platform.launcher.LauncherDiscoveryRequest; /** * Integration tests that verify support for {@link BeforeEach}, {@link AfterEach}, * {@link BeforeEachCallback}, and {@link AfterEachCallback} in the {@link JupiterTestEngine}. * * @since 5.0 * @see BeforeAndAfterTestExecutionCallbackTests */ class BeforeAndAfterEachTests extends AbstractJupiterTestEngineTests { private static final List<String> callSequence = new ArrayList<>(); private static final List<String> beforeEachMethodCallSequence = new ArrayList<>(); private static Optional<Throwable> actualExceptionInAfterEachCallback; @BeforeEach void resetCallSequence() { callSequence.clear(); beforeEachMethodCallSequence.clear(); actualExceptionInAfterEachCallback = null; } @Test void beforeEachAndAfterEachCallbacks() { LauncherDiscoveryRequest request = request().selectors(selectClass(OuterTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(2, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(2, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(0, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( // OuterTestCase "fooBeforeEachCallback", "barBeforeEachCallback", "beforeEachMethod", "testOuter", "afterEachMethod", "barAfterEachCallback", "fooAfterEachCallback", // InnerTestCase "fooBeforeEachCallback", "barBeforeEachCallback", "fizzBeforeEachCallback", "beforeEachMethod", "beforeEachInnerMethod", "testInner", "afterEachInnerMethod", "afterEachMethod", "fizzAfterEachCallback", "barAfterEachCallback", "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on } @Test void beforeEachAndAfterEachCallbacksDeclaredOnSuperclassAndSubclass() { LauncherDiscoveryRequest request = request().selectors(selectClass(ChildTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(1, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(1, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(0, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( "fooBeforeEachCallback", "barBeforeEachCallback", "testChild", "barAfterEachCallback", "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on } @Test void beforeEachAndAfterEachCallbacksDeclaredOnInterfaceAndClass() { LauncherDiscoveryRequest request = request().selectors(selectClass(TestInterfaceTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(2, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(2, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(0, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( // Test Interface "fooBeforeEachCallback", "barBeforeEachCallback", "defaultTestMethod", "barAfterEachCallback", "fooAfterEachCallback", // Test Class "fooBeforeEachCallback", "barBeforeEachCallback", "localTestMethod", "barAfterEachCallback", "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on } @Test void beforeEachCallbackThrowsAnException() { LauncherDiscoveryRequest request = request().selectors( selectClass(ExceptionInBeforeEachCallbackTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(1, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(0, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(1, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( "fooBeforeEachCallback", "exceptionThrowingBeforeEachCallback", // throws an exception. // barBeforeEachCallback should not get invoked. // beforeEachMethod should not get invoked. // test should not get invoked. // afterEachMethod should not get invoked. "barAfterEachCallback", "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on assertTrue(actualExceptionInAfterEachCallback.isPresent(), "test exception should be present"); assertEquals(EnigmaException.class, actualExceptionInAfterEachCallback.get().getClass()); } @Test void afterEachCallbackThrowsAnException() { LauncherDiscoveryRequest request = request().selectors( selectClass(ExceptionInAfterEachCallbackTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(1, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(0, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(1, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( "fooBeforeEachCallback", "barBeforeEachCallback", "beforeEachMethod", "test", "afterEachMethod", "barAfterEachCallback", "exceptionThrowingAfterEachCallback", // throws an exception. "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on assertTrue(actualExceptionInAfterEachCallback.isPresent(), "test exception should be present"); assertEquals(EnigmaException.class, actualExceptionInAfterEachCallback.get().getClass()); } @Test void beforeEachMethodThrowsAnException() { LauncherDiscoveryRequest request = request().selectors( selectClass(ExceptionInBeforeEachMethodTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(1, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(0, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(1, eventRecorder.getTestFailedCount(), "# tests failed"); // Since the JVM does not guarantee the order in which methods are // returned via reflection (and since JUnit Jupiter does not yet // support ordering of @BeforeEach methods), we have to figure out // which @BeforeEach method got executed first in order to determine // the expected call sequence. // @formatter:off List<String> list1 = asList( "fooBeforeEachCallback", "beforeEachMethod1", // throws an exception. // "beforeEachMethod2" should not get invoked // test should not get invoked. "afterEachMethod", "fooAfterEachCallback" ); List<String> list2 = asList( "fooBeforeEachCallback", "beforeEachMethod2", "beforeEachMethod1", // throws an exception. // test should not get invoked. "afterEachMethod", "fooAfterEachCallback" ); // @formatter:on List<String> expected = beforeEachMethodCallSequence.get(0).equals("beforeEachMethod1") ? list1 : list2; assertEquals(expected, callSequence, "wrong call sequence"); assertTrue(actualExceptionInAfterEachCallback.isPresent(), "test exception should be present"); assertEquals(EnigmaException.class, actualExceptionInAfterEachCallback.get().getClass()); } @Test void afterEachMethodThrowsAnException() { LauncherDiscoveryRequest request = request().selectors( selectClass(ExceptionInAfterEachMethodTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(1, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(0, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(1, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( "fooBeforeEachCallback", "beforeEachMethod", "test", "afterEachMethod", // throws an exception. "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on assertTrue(actualExceptionInAfterEachCallback.isPresent(), "test exception should be present"); assertEquals(EnigmaException.class, actualExceptionInAfterEachCallback.get().getClass()); } @Test void testMethodThrowsAnException() { LauncherDiscoveryRequest request = request().selectors( selectClass(ExceptionInTestMethodTestCase.class)).build(); ExecutionEventRecorder eventRecorder = executeTests(request); assertEquals(1, eventRecorder.getTestStartedCount(), "# tests started"); assertEquals(0, eventRecorder.getTestSuccessfulCount(), "# tests succeeded"); assertEquals(0, eventRecorder.getTestSkippedCount(), "# tests skipped"); assertEquals(0, eventRecorder.getTestAbortedCount(), "# tests aborted"); assertEquals(1, eventRecorder.getTestFailedCount(), "# tests failed"); // @formatter:off assertEquals(asList( "fooBeforeEachCallback", "beforeEachMethod", "test", // throws an exception. "afterEachMethod", "fooAfterEachCallback" ), callSequence, "wrong call sequence"); // @formatter:on assertTrue(actualExceptionInAfterEachCallback.isPresent(), "test exception should be present"); assertEquals(EnigmaException.class, actualExceptionInAfterEachCallback.get().getClass()); } // ------------------------------------------------------------------------- @ExtendWith(FooMethodLevelCallbacks.class) private static class ParentTestCase { } @ExtendWith(BarMethodLevelCallbacks.class) private static class ChildTestCase extends ParentTestCase { @Test void test() { callSequence.add("testChild"); } } @ExtendWith(FooMethodLevelCallbacks.class) private interface TestInterface { @Test default void defaultTest() { callSequence.add("defaultTestMethod"); } } @ExtendWith(BarMethodLevelCallbacks.class) private static class TestInterfaceTestCase implements TestInterface { @Test void localTest() { callSequence.add("localTestMethod"); } } @ExtendWith({ FooMethodLevelCallbacks.class, BarMethodLevelCallbacks.class }) private static class OuterTestCase { @BeforeEach void beforeEach() { callSequence.add("beforeEachMethod"); } @Test void testOuter() { callSequence.add("testOuter"); } @AfterEach void afterEach() { callSequence.add("afterEachMethod"); } @Nested @ExtendWith(FizzMethodLevelCallbacks.class) class InnerTestCase { @BeforeEach void beforeEachInnerMethod() { callSequence.add("beforeEachInnerMethod"); } @Test void testInner() { callSequence.add("testInner"); } @AfterEach void afterEachInnerMethod() { callSequence.add("afterEachInnerMethod"); } } } @ExtendWith({ FooMethodLevelCallbacks.class, ExceptionThrowingBeforeEachCallback.class, BarMethodLevelCallbacks.class }) private static class ExceptionInBeforeEachCallbackTestCase { @BeforeEach void beforeEach() { callSequence.add("beforeEachMethod"); } @Test void test() { callSequence.add("test"); } @AfterEach void afterEach() { callSequence.add("afterEachMethod"); } } @ExtendWith({ FooMethodLevelCallbacks.class, ExceptionThrowingAfterEachCallback.class, BarMethodLevelCallbacks.class }) private static class ExceptionInAfterEachCallbackTestCase { @BeforeEach void beforeEach() { callSequence.add("beforeEachMethod"); } @Test void test() { callSequence.add("test"); } @AfterEach void afterEach() { callSequence.add("afterEachMethod"); } } @ExtendWith(FooMethodLevelCallbacks.class) private static class ExceptionInBeforeEachMethodTestCase { @BeforeEach void beforeEach1() { beforeEachMethodCallSequence.add("beforeEachMethod1"); callSequence.add("beforeEachMethod1"); throw new EnigmaException("@BeforeEach"); } @BeforeEach void beforeEach2() { beforeEachMethodCallSequence.add("beforeEachMethod2"); callSequence.add("beforeEachMethod2"); } @Test void test() { callSequence.add("test"); } @AfterEach void afterEach() { callSequence.add("afterEachMethod"); } } @ExtendWith(FooMethodLevelCallbacks.class) private static class ExceptionInAfterEachMethodTestCase { @BeforeEach void beforeEach() { callSequence.add("beforeEachMethod"); } @Test void test() { callSequence.add("test"); } @AfterEach void afterEach() { callSequence.add("afterEachMethod"); throw new EnigmaException("@AfterEach"); } } @ExtendWith(FooMethodLevelCallbacks.class) private static class ExceptionInTestMethodTestCase { @BeforeEach void beforeEach() { callSequence.add("beforeEachMethod"); } @Test void test() { callSequence.add("test"); throw new EnigmaException("@Test"); } @AfterEach void afterEach() { callSequence.add("afterEachMethod"); } } // ------------------------------------------------------------------------- private static class FooMethodLevelCallbacks implements BeforeEachCallback, AfterEachCallback { @Override public void beforeEach(TestExtensionContext context) { callSequence.add("fooBeforeEachCallback"); } @Override public void afterEach(TestExtensionContext context) { callSequence.add("fooAfterEachCallback"); actualExceptionInAfterEachCallback = context.getTestException(); } } private static class BarMethodLevelCallbacks implements BeforeEachCallback, AfterEachCallback { @Override public void beforeEach(TestExtensionContext context) { callSequence.add("barBeforeEachCallback"); } @Override public void afterEach(TestExtensionContext context) { callSequence.add("barAfterEachCallback"); } } private static class FizzMethodLevelCallbacks implements BeforeEachCallback, AfterEachCallback { @Override public void beforeEach(TestExtensionContext context) { callSequence.add("fizzBeforeEachCallback"); } @Override public void afterEach(TestExtensionContext context) { callSequence.add("fizzAfterEachCallback"); } } private static class ExceptionThrowingBeforeEachCallback implements BeforeEachCallback { @Override public void beforeEach(TestExtensionContext context) { callSequence.add("exceptionThrowingBeforeEachCallback"); throw new EnigmaException("BeforeEachCallback"); } } private static class ExceptionThrowingAfterEachCallback implements AfterEachCallback { @Override public void afterEach(TestExtensionContext context) { callSequence.add("exceptionThrowingAfterEachCallback"); throw new EnigmaException("AfterEachCallback"); } } @SuppressWarnings("serial") private static class EnigmaException extends RuntimeException { EnigmaException(String message) { super(message); } } }