Skip to content

Commit

Permalink
Before/AfterAll callbacks work. Before/AfterAll methods not yet.
Browse files Browse the repository at this point in the history
------------------------------------------------------------------------
On behalf of the community, the JUnit Lambda Team thanks
AdNovum Informatik AG (http://www.adnovum.ch) for supporting the
JUnit crowdfunding campaign!
------------------------------------------------------------------------
  • Loading branch information
jlink committed Dec 17, 2015
1 parent b023d5c commit c2d9a53
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 79 deletions.
Expand Up @@ -12,11 +12,11 @@

public interface Container<C extends EngineExecutionContext> {

default C beforeAll(C context) {
default C beforeAll(C context) throws Throwable {
return context;
}

default C afterAll(C context) {
default C afterAll(C context) throws Throwable {
return context;
}

Expand Down
Expand Up @@ -11,13 +11,13 @@
package org.junit.gen5.engine.junit5;

import static java.util.Arrays.asList;
import static org.junit.gen5.api.Assertions.assertEquals;
import static org.junit.gen5.engine.TestPlanSpecification.*;

import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.gen5.api.AfterAll;
import org.junit.gen5.api.BeforeAll;
import org.junit.gen5.api.Test;
Expand All @@ -28,92 +28,98 @@
import org.junit.gen5.engine.TestPlanSpecification;

/**
* Integration tests that verify support of {@link BeforeAll}, {@link AfterAll},
* and {@link BeforeAllExtensionPoint} in the {@link JUnit5TestEngine}.
* Integration tests that verify support of {@link BeforeAll}, {@link AfterAll}, and {@link BeforeAllExtensionPoint} in
* the {@link JUnit5TestEngine}.
*
* @since 5.0
*/
@Ignore("https://github.com/junit-team/junit-lambda/issues/39")
public class ClassLevelCallbackTests extends AbstractJUnit5TestEngineTestCase {

@org.junit.Before
public void reset() {
preBeforeAllMethods.clear();
postAfterAllMethods.clear();
}

@org.junit.Test
public void beforeAllAndAfterAllCallbacksWithTestInstancePerMethod() {
public void beforeAllAndAfterAllCallbacks() {
TestPlanSpecification spec = build(forClass(InstancePerMethodTestCase.class));

TrackingEngineExecutionListener listener = executeTests(spec, 2);

Assert.assertEquals("# tests started", 1, listener.testStartedCount.get());
Assert.assertEquals("# tests succeeded", 1, listener.testSucceededCount.get());
Assert.assertEquals("# tests skipped", 0, listener.testSkippedCount.get());
Assert.assertEquals("# tests aborted", 0, listener.testAbortedCount.get());
Assert.assertEquals("# tests failed", 0, listener.testFailedCount.get());

Assert.assertTrue("@BeforeAll was not invoked", InstancePerMethodTestCase.beforeAllInvoked);
Assert.assertTrue("@AfterAll was not invoked", InstancePerMethodTestCase.afterAllInvoked);

Assert.assertEquals("preBeforeAll()", asList("foo", "bar"), preBeforeAllMethods);
Assert.assertEquals("postAfterAll()", asList("bar", "foo"), postAfterAllMethods);
TrackingEngineExecutionListener listener = executeTests(spec, 3);

Assert.assertEquals("# tests started", 2, listener.testStartedCount.get());
Assert.assertEquals("# tests succeeded", 2, listener.testSucceededCount.get());

// @formatter:off
assertEquals(asList(

// "outermostBefore",
"fooBeforeAll",
"barBeforeAll",
// "beforeAllMethod",
// "fizzBefore",
// "beforeInnerMethod",
// "innermostBefore",
"firstTest",
"secondTest",
// "innermostAfter",
// "afterInnerMethod",
// "fizzAfter",
// "afterAllMethod",
"barAfterAll",
"fooAfterAll"
// "outermostAfter"

), callSequence, "wrong call sequence");
// @formatter:on
}

// -------------------------------------------------------------------

private static List<String> callSequence = new ArrayList<>();

@ExtendWith({ FooClassLevelCallbacks.class, BarClassLevelCallbacks.class })
private static class InstancePerMethodTestCase {

static boolean beforeAllInvoked = false;

static boolean afterAllInvoked = false;

@BeforeAll
// MUST be static for TestInstance.Lifecycle.PER_METHOD!
static void beforeAll() {
beforeAllInvoked = true;
callSequence.add("beforeAllMethod");
}

@AfterAll
// MUST be static for TestInstance.Lifecycle.PER_METHOD!
static void afterAll() {
afterAllInvoked = true;
callSequence.add("afterAllMethod");
}

@Test
void alwaysPasses() {
/* no-op */
void firstTest() {
callSequence.add("firstTest");
}
}

private static List<String> preBeforeAllMethods = new ArrayList<>();
private static List<String> postAfterAllMethods = new ArrayList<>();
@Test
void secondTest() {
callSequence.add("secondTest");

}
}

private static class FooClassLevelCallbacks implements BeforeAllExtensionPoint, AfterAllExtensionPoint {

@Override
public void beforeAll(ContainerExtensionContext testExecutionContext) {
preBeforeAllMethods.add("foo");
callSequence.add("fooBeforeAll");
}

@Override
public void afterAll(ContainerExtensionContext testExecutionContext) {
postAfterAllMethods.add("foo");
callSequence.add("fooAfterAll");
}
}

private static class BarClassLevelCallbacks implements BeforeAllExtensionPoint, AfterAllExtensionPoint {

@Override
public void beforeAll(ContainerExtensionContext testExecutionContext) {
preBeforeAllMethods.add("bar");
callSequence.add("barBeforeAll");
}

@Override
public void afterAll(ContainerExtensionContext testExecutionContext) {
postAfterAllMethods.add("bar");
callSequence.add("barAfterAll");
}
}

Expand Down
Expand Up @@ -14,14 +14,18 @@
import static org.junit.gen5.engine.junit5.descriptor.MethodContextImpl.methodContext;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.junit.gen5.api.AfterEach;
import org.junit.gen5.api.BeforeEach;
import org.junit.gen5.api.extension.AfterAllExtensionPoint;
import org.junit.gen5.api.extension.AfterEachExtensionPoint;
import org.junit.gen5.api.extension.BeforeAllExtensionPoint;
import org.junit.gen5.api.extension.BeforeEachExtensionPoint;
import org.junit.gen5.api.extension.ContainerExtensionContext;
import org.junit.gen5.api.extension.ExtensionPoint;
import org.junit.gen5.api.extension.TestExtensionContext;
import org.junit.gen5.commons.util.Preconditions;
Expand All @@ -33,8 +37,10 @@
import org.junit.gen5.engine.TestTag;
import org.junit.gen5.engine.junit5.execution.JUnit5EngineExecutionContext;
import org.junit.gen5.engine.junit5.execution.MethodInvoker;
import org.junit.gen5.engine.junit5.execution.RegisteredExtensionPoint;
import org.junit.gen5.engine.junit5.execution.TestExtensionRegistry;
import org.junit.gen5.engine.junit5.execution.TestInstanceProvider;
import org.junit.gen5.engine.junit5.execution.ThrowingConsumer;

/**
* {@link TestDescriptor} for tests based on Java classes.
Expand Down Expand Up @@ -86,34 +92,68 @@ public boolean isContainer() {
}

@Override
public JUnit5EngineExecutionContext beforeAll(JUnit5EngineExecutionContext context) {
public JUnit5EngineExecutionContext beforeAll(JUnit5EngineExecutionContext context) throws Throwable {
TestExtensionRegistry newExtensionRegistry = populateNewTestExtensionRegistryFromExtendWith(testClass,
context.getTestExtensionRegistry());
registerBeforeEachMethods(newExtensionRegistry);
registerAfterEachMethods(newExtensionRegistry);

context = context.extend().withTestExtensionRegistry(newExtensionRegistry).build();

ContainerExtensionContext containerExtensionContext = new ClassBasedContainerExtensionContext(
context.getExtensionContext(), this);

invokeBeforeAllExtensionPoints(newExtensionRegistry, containerExtensionContext);

// @formatter:off
return context.extend()
.withTestInstanceProvider(testInstanceProvider(context))
.withExtensionContext(new ClassBasedContainerExtensionContext(context.getExtensionContext(), this))
.withExtensionContext(containerExtensionContext)
.build();
// @formatter:on
}

@Override
public JUnit5EngineExecutionContext afterAll(JUnit5EngineExecutionContext context) throws Throwable {
List<Throwable> throwablesCollector = new LinkedList<>();
try {
invokeAfterAllExtensionPoints(context.getTestExtensionRegistry(),
(ContainerExtensionContext) context.getExtensionContext(), throwablesCollector);
}
catch (Throwable throwable) {
throwablesCollector.add(throwable);
}

throwIfAnyThrowablePresent(throwablesCollector);

return context;
}

protected TestInstanceProvider testInstanceProvider(JUnit5EngineExecutionContext context) {
return () -> ReflectionUtils.newInstance(testClass);
}

private void registerAfterEachMethods(TestExtensionRegistry extensionRegistry) {
List<Method> afterEachMethods = findAnnotatedMethods(testClass, AfterEach.class, MethodSortOrder.HierarchyDown);
afterEachMethods.stream().forEach(method -> {
AfterEachExtensionPoint extensionPoint = testExtensionContext -> {
runMethodInExtensionContext(method, testExtensionContext, extensionRegistry);
};
extensionRegistry.registerExtension(extensionPoint, ExtensionPoint.Position.DEFAULT, method.getName());
});
private void invokeBeforeAllExtensionPoints(TestExtensionRegistry newTestExtensionRegistry,
ContainerExtensionContext containerExtensionContext) throws Throwable {
ThrowingConsumer<RegisteredExtensionPoint<BeforeAllExtensionPoint>> applyBeforeEach = registeredExtensionPoint -> {
registeredExtensionPoint.getExtensionPoint().beforeAll(containerExtensionContext);
};
newTestExtensionRegistry.applyExtensionPoints(BeforeAllExtensionPoint.class,
TestExtensionRegistry.ApplicationOrder.FORWARD, applyBeforeEach);
}

private void invokeAfterAllExtensionPoints(TestExtensionRegistry newTestExtensionRegistry,
ContainerExtensionContext containerExtensionContext, List<Throwable> throwablesCollector) throws Throwable {
ThrowingConsumer<RegisteredExtensionPoint<AfterAllExtensionPoint>> applyAfterAll = registeredExtensionPoint -> {
try {
registeredExtensionPoint.getExtensionPoint().afterAll(containerExtensionContext);
}
catch (Throwable t) {
throwablesCollector.add(t);
}
};
newTestExtensionRegistry.applyExtensionPoints(AfterAllExtensionPoint.class,
TestExtensionRegistry.ApplicationOrder.BACKWARD, applyAfterAll);
}

private void registerBeforeEachMethods(TestExtensionRegistry extensionRegistry) {
Expand All @@ -127,6 +167,16 @@ private void registerBeforeEachMethods(TestExtensionRegistry extensionRegistry)
});
}

private void registerAfterEachMethods(TestExtensionRegistry extensionRegistry) {
List<Method> afterEachMethods = findAnnotatedMethods(testClass, AfterEach.class, MethodSortOrder.HierarchyDown);
afterEachMethods.stream().forEach(method -> {
AfterEachExtensionPoint extensionPoint = testExtensionContext -> {
runMethodInExtensionContext(method, testExtensionContext, extensionRegistry);
};
extensionRegistry.registerExtension(extensionPoint, ExtensionPoint.Position.DEFAULT, method.getName());
});
}

private void runMethodInExtensionContext(Method method, TestExtensionContext testExtensionContext,
TestExtensionRegistry extensionRegistry) {
Optional<Object> optionalInstance = ReflectionUtils.getOuterInstance(testExtensionContext.getTestInstance(),
Expand Down
Expand Up @@ -69,4 +69,12 @@ protected TestExtensionRegistry populateNewTestExtensionRegistryFromExtendWith(A
return TestExtensionRegistry.newRegistryFrom(existingTestExtensionRegistry, extensionClasses);
}

protected void throwIfAnyThrowablePresent(List<Throwable> throwablesCollector) throws Throwable {
if (!throwablesCollector.isEmpty()) {
Throwable t = throwablesCollector.get(0);
throwablesCollector.stream().skip(1).forEach(t::addSuppressed);
throw t;
}
}

}
Expand Up @@ -106,38 +106,15 @@ public JUnit5EngineExecutionContext execute(JUnit5EngineExecutionContext context

invokeAfterEachExtensionPoints(newTestExtensionRegistry, testExtensionContext, throwablesCollector);

if (!throwablesCollector.isEmpty()) {
Throwable t = throwablesCollector.get(0);
throwablesCollector.stream().skip(1).forEach(t::addSuppressed);
throw t;
}
throwIfAnyThrowablePresent(throwablesCollector);

return newContext;
}

protected void invokeAfterEachExtensionPoints(TestExtensionRegistry newTestExtensionRegistry,
TestExtensionContext testExtensionContext, List<Throwable> throwables) throws Throwable {
ThrowingConsumer<RegisteredExtensionPoint<AfterEachExtensionPoint>> applyAfterEach = registeredExtensionPoint -> {
try {
registeredExtensionPoint.getExtensionPoint().afterEach(testExtensionContext);
}
catch (Throwable t) {
throwables.add(t);
}
};
newTestExtensionRegistry.applyExtensionPoints(AfterEachExtensionPoint.class,
TestExtensionRegistry.ApplicationOrder.BACKWARD, applyAfterEach);
}

protected void invokeBeforeEachExtensionPoints(TestExtensionRegistry newTestExtensionRegistry,
private void invokeBeforeEachExtensionPoints(TestExtensionRegistry newTestExtensionRegistry,
TestExtensionContext testExtensionContext) throws Throwable {
ThrowingConsumer<RegisteredExtensionPoint<BeforeEachExtensionPoint>> applyBeforeEach = registeredExtensionPoint -> {
try {
registeredExtensionPoint.getExtensionPoint().beforeEach(testExtensionContext);
}
catch (Exception e) { //TODO: Non RTEs should be allowed
throw new RuntimeException(e);
}
registeredExtensionPoint.getExtensionPoint().beforeEach(testExtensionContext);
};
newTestExtensionRegistry.applyExtensionPoints(BeforeEachExtensionPoint.class,
TestExtensionRegistry.ApplicationOrder.FORWARD, applyBeforeEach);
Expand All @@ -155,4 +132,18 @@ private void invokeTestMethod(TestExtensionContext testExtensionContext,
}
}

private void invokeAfterEachExtensionPoints(TestExtensionRegistry newTestExtensionRegistry,
TestExtensionContext testExtensionContext, List<Throwable> throwablesCollector) throws Throwable {
ThrowingConsumer<RegisteredExtensionPoint<AfterEachExtensionPoint>> applyAfterEach = registeredExtensionPoint -> {
try {
registeredExtensionPoint.getExtensionPoint().afterEach(testExtensionContext);
}
catch (Throwable t) {
throwablesCollector.add(t);
}
};
newTestExtensionRegistry.applyExtensionPoints(AfterEachExtensionPoint.class,
TestExtensionRegistry.ApplicationOrder.BACKWARD, applyAfterEach);
}

}

0 comments on commit c2d9a53

Please sign in to comment.