运行相同类但具有不同初始条件的测试套件

在JUnit 4中,我希望编写一个由同一测试用例的多种风格组成的测试套件,每种风格的初始条件都不同。 这是一个例子:

import java.io.File; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({MultiInputClientServerIntegrationTest.NormalInput.class, MultiInputClientServerIntegrationTest.SimulationHashIssue.class}) public class MultiInputClientServerIntegrationTest { @RunWith(Suite.class) @SuiteClasses({TestClientServerIntegration.class}) public class NormalInput {} @RunWith(Suite.class) @SuiteClasses({TestClientServerIntegration.class}) public class SimulationHashIssue { public SimulationHashIssue() { TestClientServerIntegration.simulation = new File("test\\BEECHA01\\sim2.zip"); TestClientServerIntegration.inputFile = "files\\config.in"; } } } 

如您所见,两个内部类都具有TestClientServerIntegration.class SuiteClasses,但第二个内部类正在更改一些静态变量值。 我发现这个构造函数永远不会被调用,因此这些静态函数永远不会被更改。

我的最终目标是使用多种类型的输入反复运行此TestClientServerIntegration.class 。 如果我能以这种方式运行测试套件,那将是理想的 – 所以希望它是可能的。 我想尽可能少地攻击JUnit,但是需要完成的工作将会完成。

我解决了! JUnit在行动中的帮助很大。 这是我的代码:

 /** * The Class MultiInputClientServerIntegrationTest. */ @RunWith(Suite.class) @SuiteClasses({MultiInputClientServerIntegrationTest.NormalInput.class, MultiInputClientServerIntegrationTest.BEECHA01SimulationHashIssue.class}) public class MultiInputClientServerIntegrationTest { /** * The Class NormalInput. */ @RunWith(Suite.class) @SuiteClasses({TestClientServerIntegration.class}) public class NormalInput {} /** * The Class BEECHA01SimulationHashIssue. */ // @RunWith(Suite.class) @RunWith(InterceptorRunner.class) @SuiteClasses({TestClientServerIntegration.class}) @InterceptorClasses({BEECHA01SimulationHashIssueInterceptor.class}) public static class BEECHA01SimulationHashIssue extends TestClientServerIntegration { } /** * The Class BEECHA01SimulationHashIssueInterceptor. */ public static class BEECHA01SimulationHashIssueInterceptor implements Interceptor { static File sim = new File("test\\BEECHA01\\6dof_Block20_FD2_2.zip"); static String in = "BEECHA01\\config.in"; /* * (non-Javadoc) * * @see test.northgrum.globalhawk.simulation.Interceptor#interceptBefore() */ @Override public void interceptBefore() { if (!TestClientServerIntegration.simulation.equals(sim) || !TestClientServerIntegration.inputFile.equals(in)) { TestClientServerIntegration.simulation = sim; TestClientServerIntegration.inputFile = in; System.out.println("Test set up with BEECHA01 Initial Parameters"); } } /* * (non-Javadoc) * * @see test.northgrum.globalhawk.simulation.Interceptor#interceptAfter() */ @Override public void interceptAfter() {} } } 

特殊跑步者的位置是:

 /** * This interface is used to declare the methods for every interceptor. * * @version $Id: Interceptor.java 201 2009-02-15 19:18:09Z paranoid12 $ */ public interface Interceptor { /** * This method will be called before every test - we can implement our own logic in every * implementation. */ public void interceptBefore(); /** * This method will be called after every test - we can implement our own logic in every * implementation. */ public void interceptAfter(); } 

和,

 /** * A custom runner for JUnit4.5 in which we demonstrate the interceptor pattern. * * @version $Id: InterceptorRunner.java 201 2009-02-15 19:18:09Z paranoid12 $ */ public class InterceptorRunner extends BlockJUnit4ClassRunner { /** * This is the InterceptorClasses annotation, which serves to hold our interceptor class * implementations. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface InterceptorClasses { /** * Value. * * @return the classes to be run */ public Class[] value(); } /** * This constructor is a must. * * @param clazz the test-case class * @throws InitializationError the initialization error */ public InterceptorRunner(Class clazz) throws InitializationError { super(clazz); } /** * Override the methodInvoker, so that when it is called we wrap the statement with our own. * * @param method the test method * @param test the test-case * @return the statement */ @Override public Statement methodInvoker(FrameworkMethod method, Object test) { InterceptorStatement statement = new InterceptorStatement(super.methodInvoker(method, test)); InterceptorClasses annotation = test.getClass().getAnnotation(InterceptorClasses.class); Class[] klasez = annotation.value(); try { for (Class klaz : klasez) { statement.addInterceptor((Interceptor) klaz.newInstance()); } } catch (IllegalAccessException ilex) { ilex.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return statement; } } /** * A statement for our custom runner. * * @version $Id: InterceptorStatement.java 201 2009-02-15 19:18:09Z paranoid12 $ */ public class InterceptorStatement extends Statement { /** * A wrapping invoker that will procede the execution, once we execute our interceptors. */ private final Statement invoker; /** * A list of interceptors that will be executed before the other statements. */ private List interceptors = new ArrayList(); /** * A constructor that takes another invoker to wrap our statement. * * @param invoker the invoker */ public InterceptorStatement(Statement invoker) { this.invoker = invoker; } /** * We override this method to call our interceptors, and then evaluate the wrapping invoker. * * @throws Throwable the throwable */ @Override public void evaluate() throws Throwable { for (Interceptor interceptor : interceptors) { interceptor.interceptBefore(); } invoker.evaluate(); for (Interceptor interceptor : interceptors) { interceptor.interceptAfter(); } } /** * Add another interceptor to the list of interceptors we have. * * @param interceptor we want to add */ public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } } 

实际上有什么帮助切换到JUnit 4.10,因为它提供了更详细的错误消息。 无论如何,这里的主要区别是我的“自定义输入”测试扩展了实际测试。 然后我创建了一个拦截器,它可以重载@Before和@After方法,并且可以在每个@Test之前更改参数。

事实上,我更喜欢一些只是超载每个@BeforeClass的东西,但乞丐不是选择者。 这足够好,工作正常。 它适用于Eclipse。 希望我会遇到@BeforeClass的钩子并改为工作。

替代解决方案呢?

1.使用模板模式提取抽象测试类,并使初始条件准备成抽象方法。

2.每个测试用例扩展模板并覆盖初始条件准备的实现。

3.将它们全部分组到测试套件中。

哦,保持简单! 你的测试课可以有

  • 一个私有方法,它实际上运行测试,并且具有与您想要从一个测试更改为下一个测试的各种事物相对应的参数;
  • 几个公共测试方法,每个方法只调用私有方法,具有不同的参数值。