Skip to content

Commit

Permalink
ARQ-1818 Add JUnit Rules lifecycles
Browse files Browse the repository at this point in the history
Add support for custom lifecycles provided by the Testing
framework. JUnit can now fire @rules related lifecycles.

Custom lifecycles should inherit the Before/AfterTestLifecycleEvent
so extensions can get callbacks without relying on Test
framework specific events.
  • Loading branch information
aslakknutsen committed Feb 11, 2015
1 parent 603bdf0 commit 606b4b2
Show file tree
Hide file tree
Showing 23 changed files with 634 additions and 62 deletions.
Expand Up @@ -32,8 +32,8 @@
import org.jboss.arquillian.container.spi.event.StartClassContainers;
import org.jboss.arquillian.container.spi.event.StartSuiteContainers;
import org.jboss.arquillian.container.spi.event.StopClassContainers;
import org.jboss.arquillian.container.spi.event.StopSuiteContainers;
import org.jboss.arquillian.container.spi.event.StopManualContainers;
import org.jboss.arquillian.container.spi.event.StopSuiteContainers;
import org.jboss.arquillian.container.spi.event.UnDeployManagedDeployments;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.impl.client.deployment.event.GenerateDeployment;
Expand All @@ -42,12 +42,12 @@
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.core.spi.EventContext;
import org.jboss.arquillian.test.spi.event.suite.After;
import org.jboss.arquillian.test.spi.event.suite.AfterClass;
import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.jboss.arquillian.test.spi.event.suite.AfterTestLifecycleEvent;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
import org.jboss.arquillian.test.spi.event.suite.BeforeTestLifecycleEvent;
import org.jboss.arquillian.test.spi.event.suite.Test;
import org.jboss.arquillian.test.spi.event.suite.TestEvent;

Expand Down Expand Up @@ -119,7 +119,7 @@ public void execute(@Observes AfterClass event)
*
* Activate Container and Deployment context on Before / Test / After events
*/
public void createBeforeContext(@Observes EventContext<Before> context)
public void createBeforeContext(@Observes EventContext<BeforeTestLifecycleEvent> context)
{
createContext(context);
}
Expand All @@ -129,12 +129,12 @@ public void createTestContext(@Observes EventContext<Test> context)
createContext(context);
}

public void createAfterContext(@Observes EventContext<After> context)
public void createAfterContext(@Observes EventContext<AfterTestLifecycleEvent> context)
{
createContext(context);
}

private void createContext(EventContext<? extends TestEvent> context)
private void createContext(EventContext<? extends TestEvent> context)
{
try
{
Expand Down
Expand Up @@ -17,7 +17,7 @@
package org.jboss.arquillian.container.test.impl.execution;

import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.test.spi.event.suite.After;
import org.jboss.arquillian.test.spi.event.suite.AfterTestLifecycleEvent;

/**
* Observer that executes the After phase on the test case.
Expand All @@ -30,7 +30,7 @@
*/
public class AfterLifecycleEventExecuter
{
public void on(@Observes(precedence = 100) After event) throws Throwable
public void on(@Observes(precedence = 100) AfterTestLifecycleEvent event) throws Throwable
{
event.getExecutor().invoke();
}
Expand Down
Expand Up @@ -17,7 +17,7 @@
package org.jboss.arquillian.container.test.impl.execution;

import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.jboss.arquillian.test.spi.event.suite.BeforeTestLifecycleEvent;

/**
* Observer that executes the Before phase on the test case.
Expand All @@ -30,7 +30,7 @@
*/
public class BeforeLifecycleEventExecuter
{
public void on(@Observes(precedence = -100) Before event) throws Throwable
public void on(@Observes(precedence = -100) BeforeTestLifecycleEvent event) throws Throwable
{
event.getExecutor().invoke();
}
Expand Down
Expand Up @@ -22,10 +22,10 @@
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.test.spi.event.suite.After;
import org.jboss.arquillian.test.spi.event.suite.AfterClass;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.jboss.arquillian.test.spi.event.suite.AfterTestLifecycleEvent;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
import org.jboss.arquillian.test.spi.event.suite.BeforeTestLifecycleEvent;
import org.jboss.arquillian.test.spi.event.suite.LifecycleEvent;
import org.jboss.arquillian.test.spi.event.suite.TestLifecycleEvent;

Expand Down Expand Up @@ -65,15 +65,15 @@ public void on(@Observes(precedence = 100) AfterClass event) throws Throwable
execute(event);
}

public void on(@Observes(precedence = -100) Before event) throws Throwable
public void on(@Observes(precedence = -100) BeforeTestLifecycleEvent event) throws Throwable
{
if(isRunAsClient(event) || isLocalContainer())
{
execute(event);
}
}

public void on(@Observes(precedence = 100) After event) throws Throwable
public void on(@Observes(precedence = 100) AfterTestLifecycleEvent event) throws Throwable
{
if(isRunAsClient(event) || isLocalContainer())
{
Expand Down
99 changes: 72 additions & 27 deletions junit/core/src/main/java/org/jboss/arquillian/junit/Arquillian.java
Expand Up @@ -23,13 +23,15 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.jboss.arquillian.junit.event.AfterRules;
import org.jboss.arquillian.junit.event.BeforeRules;
import org.jboss.arquillian.test.spi.LifecycleMethodExecutor;
import org.jboss.arquillian.test.spi.TestMethodExecutor;
import org.jboss.arquillian.test.spi.TestResult;
import org.jboss.arquillian.test.spi.TestResult.Status;
import org.jboss.arquillian.test.spi.execution.SkippedTestExecutionException;
import org.jboss.arquillian.test.spi.TestRunnerAdaptor;
import org.jboss.arquillian.test.spi.TestRunnerAdaptorBuilder;
import org.jboss.arquillian.test.spi.execution.SkippedTestExecutionException;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.MultipleFailureException;
import org.junit.internal.runners.model.ReflectiveCallable;
Expand Down Expand Up @@ -227,12 +229,53 @@ public void evaluate() throws Throwable
};
}

@Override
protected Statement withBefores(final FrameworkMethod method, final Object target, final Statement originalStatement)
{
final Statement onlyBefores = super.withBefores(method, target, new EmptyStatement());
return new Statement()
{
@Override
public void evaluate() throws Throwable
{
adaptor.before(
target,
method.getMethod(),
new StatementLifecycleExecutor(onlyBefores));
originalStatement.evaluate();
}
};
}

@Override
protected Statement withAfters(final FrameworkMethod method, final Object target, final Statement originalStatement)
{
final Statement onlyAfters = super.withAfters(method, target, new EmptyStatement());
return new Statement()
{
@Override
public void evaluate() throws Throwable
{
multiExecute
(
originalStatement,
new Statement() { @Override public void evaluate() throws Throwable
{
adaptor.after(
target,
method.getMethod(),
new StatementLifecycleExecutor(onlyAfters));
}}
);
}
};
}
@Override
@SuppressWarnings("deprecation")
protected Statement methodBlock(final FrameworkMethod method) {
Object test;
Object temp;
try {
test= new ReflectiveCallable() {
temp = new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return createTest();
Expand All @@ -241,6 +284,7 @@ protected Object runReflectiveCall() throws Throwable {
} catch (Throwable e) {
return new Fail(e);
}
final Object test = temp;
try
{
Method withRules = BlockJUnit4ClassRunner.class.getDeclaredMethod("withRules",
Expand All @@ -251,44 +295,45 @@ protected Object runReflectiveCall() throws Throwable {
statement = possiblyExpectingExceptions(method, test, statement);
statement = withPotentialTimeout(method, test, statement);

final Object testObj = test;
final Statement testStatement = statement;

Statement arounds = withBefores(method, test, testStatement);
Statement arounds = withBefores(method, test, statement);
arounds = withAfters(method, test, arounds);
arounds = (Statement)withRules.invoke(this, new Object[] {method, test, arounds});
final Statement withArounds = arounds;
final Statement stmtwithLifecycle = arounds;
final Statement stmtWithRules = (Statement)withRules.invoke(this, new Object[] {method, test, arounds});
return new Statement() {

@Override
public void evaluate() throws Throwable {
State.caughtExceptionAfterJunit(null);
final AtomicInteger integer = new AtomicInteger();
List<Throwable> exceptions = new ArrayList<Throwable>();

try {
final AtomicInteger integer = new AtomicInteger();
adaptor.before(testObj, method.getMethod(), new LifecycleMethodExecutor() {
adaptor.fireCustomLifecycle(new BeforeRules(test, method.getMethod(), new LifecycleMethodExecutor() {
@Override
public void invoke() throws Throwable {
integer.incrementAndGet();
stmtWithRules.evaluate();
}
});
try {
State.caughtExceptionAfterJunit(null);
if(integer.get() > 0) {
withArounds.evaluate();
} else {
testStatement.evaluate();
}));
// If AroundRules (includes lifecycles) were not executed, invoke only lifecycles+test
if(integer.get() == 0) {
try {
stmtwithLifecycle.evaluate();
} catch(Throwable t) {
State.caughtExceptionAfterJunit(t);
throw t;
}
}
catch (Throwable e) {
State.caughtExceptionAfterJunit(e);
exceptions.add(e);
}
} finally {
} catch(Throwable t) {
State.caughtExceptionAfterJunit(t);
exceptions.add(t);
}
finally {
try {
adaptor.after(testObj, method.getMethod(), LifecycleMethodExecutor.NO_OP);
}
catch(Throwable e) {
exceptions.add(e);
adaptor.fireCustomLifecycle(new AfterRules(test, method.getMethod(), LifecycleMethodExecutor.NO_OP));
} catch(Throwable t) {
State.caughtExceptionAfterJunit(t);
exceptions.add(t);
}
}
if(exceptions.isEmpty())
Expand Down
@@ -0,0 +1,26 @@
package org.jboss.arquillian.junit.event;

import java.lang.reflect.Method;

import org.jboss.arquillian.test.spi.LifecycleMethodExecutor;
import org.jboss.arquillian.test.spi.event.suite.AfterTestLifecycleEvent;

/**
*
* Event fired After running the JUnit rules. LifecycleMethodExecutor does not
* control anything. See BeforeRules if you want to stop rules invocation.
*
*/
public class AfterRules extends AfterTestLifecycleEvent {

/**
* @param testInstance The test case instance being tested
* @param testMethod The test method that is about to be executed
* @param executor A call back when the LifecycleMethod represented by this event should be invoked
*/
public AfterRules(Object testInstance, Method testMethod, LifecycleMethodExecutor executor)
{
super(testInstance, testMethod, executor);
}

}
@@ -0,0 +1,26 @@
package org.jboss.arquillian.junit.event;

import java.lang.reflect.Method;

import org.jboss.arquillian.test.spi.LifecycleMethodExecutor;
import org.jboss.arquillian.test.spi.event.suite.BeforeTestLifecycleEvent;

/**
*
* Event fired Before running the JUnit rules. LifecycleMethodExecutor controls if
* the Rules should be invoked or not.
*
*/
public class BeforeRules extends BeforeTestLifecycleEvent {

/**
* @param testInstance The test case instance being tested
* @param testMethod The test method that is about to be executed
* @param executor A call back when the LifecycleMethod represented by this event should be invoked
*/
public BeforeRules(Object testInstance, Method testMethod, LifecycleMethodExecutor executor)
{
super(testInstance, testMethod, executor);
}

}
Expand Up @@ -21,7 +21,7 @@
import org.jboss.arquillian.junit.State;
import org.jboss.arquillian.test.spi.TestResult;
import org.jboss.arquillian.test.spi.TestResult.Status;
import org.jboss.arquillian.test.spi.event.suite.After;
import org.jboss.arquillian.test.spi.event.suite.AfterTestLifecycleEvent;
import org.junit.internal.AssumptionViolatedException;

/**
Expand All @@ -32,7 +32,7 @@
*/
class UpdateTestResultBeforeAfter
{
public void update(@Observes(precedence = 99) EventContext<After> context, TestResult result)
public void update(@Observes(precedence = 99) EventContext<AfterTestLifecycleEvent> context, TestResult result)
{
if(State.caughtExceptionAfterJunit() != null)
{
Expand Down

0 comments on commit 606b4b2

Please sign in to comment.