I have a couple of JBehave tests that I want to run from Eclipse and Ant. In Eclipse I want to see a tree of all the different stories, scenarios and steps that are performed in the graphical output, so I added a custom runner to the tests that does this:
@RunWith(de.codecentric.jbehave.junit.monitoring.JUnitReportingRunner.class)
public class MyStoryTest extends org.jbehave.core.junit.JUnitStories
{
// ...
}
But on contrary when running the tests with Ant and in the Continuous Integration server I want to see only every whole story as a single item in the output. This is usually achieved without any annotation:
public class MyStoryTest extends JUnitStories
{
// ...
}
So how can I tell Ant (junit Ant task) to use a different runner than Eclipse? To make things more complicated: At the moment I use a test suite in Eclipse (not in Ant) to run the tests:
@RunWith(org.junit.extensions.cpsuite.ClasspathSuite.class)
@org.junit.extensions.cpsuite.ClassnameFilters("foo.mypackage.tests.*")
public class MyStoriesTestSuite
{
// Nothing more to say ;)
}
Any Ideas?
Cheers, Tilmann
A command line based tool to run tests. java junit.textui.TestRunner [-wait] TestCaseClass. TestRunner expects the name of a TestCase class as argument. If this class defines a static suite method it will be invoked and the returned test is run. Otherwise all the methods starting with "test" having no arguments are run ...
RunWith' imports @RunWith annotation from the Junit class. @RunWith annotation tells JUnit that tests should run using Cucumber class present in 'Cucumber. api. junit' package.
I did some hack a few weeks ago, that can fit your needs. I realized, that the java command, which is executed by Eclipse in case of a unit test run contains always a package in its name. So if this gives back true, probably you are running your test under Eclipse:
System.getProperty( "sun.java.command" ).contains( "org.eclipse.jdt" )
I know, its not 100 percent solution, but usually works, and its better than nothing.
I created and tested a Runner+Annotation pair for you:
Annotation:
package org.junit.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.runner.Runner;
import org.junit.runners.JUnit4;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target( ElementType.TYPE )
public @interface RunWithInEnvironment {
Class<? extends Runner> eclipse();
Class<? extends Runner> defaultRunner() default JUnit4.class;
}
By default it uses JUnit4 as defaultrunner, which is really the default for JUnit4.
The Runner, which uses the information of the annotation:
package org.junit.runners;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.junit.annotation.RunWithInEnvironment;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
public class EnvironmentDependentRunner extends Runner {
protected Class<?> testClass;
protected Runner delegate;
public EnvironmentDependentRunner(Class<?> testClass) {
super();
this.testClass = testClass;
RunWithInEnvironment annotation = findAnnotationInClassHierarchy(testClass);
assertNotNull( EnvironmentDependentRunner.class.getSimpleName() + " can be used only with test classes, that are annotated with " + RunWithInEnvironment.class.getSimpleName() + " annotation somewhere in their class hierarchy!", annotation );
Class<? extends Runner> delegateClass = null;
if ( System.getProperty( "sun.java.command" ).contains( "org.eclipse.jdt" ) && annotation.eclipse() != null ) {
delegateClass = annotation.eclipse();
}
else {
delegateClass = annotation.defaultRunner();
}
try {
Constructor<? extends Runner> constructor = delegateClass.getConstructor( Class.class );
delegate = constructor.newInstance(testClass);
} catch (NoSuchMethodException e) {
fail( delegateClass.getName() + " must contain a public constructor with a " + Class.class.getName() + " argument.");
} catch (SecurityException e) {
throw new RuntimeException("SecurityException during instantiation of " + delegateClass.getName() );
} catch (InstantiationException e) {
throw new RuntimeException("Error while creating " + delegateClass.getName() );
} catch (IllegalAccessException e) {
throw new RuntimeException("Error while creating " + delegateClass.getName() );
} catch (IllegalArgumentException e) {
throw new RuntimeException("Error while creating " + delegateClass.getName() );
} catch (InvocationTargetException e) {
throw new RuntimeException("Error while creating " + delegateClass.getName() );
}
}
private RunWithInEnvironment findAnnotationInClassHierarchy(Class<?> testClass) {
RunWithInEnvironment annotation = testClass.getAnnotation(RunWithInEnvironment.class);
if (annotation != null) {
return annotation;
}
Class<?> superClass = testClass.getSuperclass();
if (superClass != null) {
return findAnnotationInClassHierarchy(superClass);
}
return null;
}
@Override
public Description getDescription() {
return delegate.getDescription();
}
@Override
public void run(RunNotifier arg0) {
delegate.run(arg0);
}
}
And an usage example:
@RunWithInEnvironment( eclipse=JUnit4.class, defaultRunner=Parameterized.class)
@RunWith( EnvironmentDependentRunner.class)
public class FooTest {
...
}
So this test will run with JUnit4 runner in Eclipse, with Parameterized outside Eclipse.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With