0

我一直在设置一些合同 JUnit 4 测试(遵循回答这个问题的建议) - 例如,如果我有一个接口(我在示例中包含了泛型,因为我在我的项目中使用它们) - 但是,这个是一个显着简化的示例:

public interface MyInterface<T> {
  public T myMethod();
}

我可以创建一个抽象的合同测试 - 例如:

public abstract class AbstractMyInterfaceTest<T> {

  private final MyInterface<T> _impl;  
  // plus, store stuff to test against;

  public AbstractMyInterfaceTest(MyInterface<T> impl, ... stuff to test against){
    _impl = impl;
    // stuff to test against...
  } 

  @Test
  public void testMyMethod(){
    // test some stuff...
  }
}

...并为每个实现(我正在运行@RunWith(Parameterized.class))扩展这个抽象测试类。我还将一些变量传递给抽象测试类来测试接口的实现。

然而,实际上,一些接口返回的对象是其他接口的实现,我希望能够使用该接口的抽象合约类来测试这个实现(......并针对相关变量)。例如,一个方法MyInterface可能返回一个迭代器——它是一个接口。我有一个单独的AbstractIteratorTest,它针对一组值运行 Iterator 的合同测试,并且我想检查实现Iterator返回的返回值是否通过了预期的一组值MyInterface的合同测试。AbstractIteratorTest

目前,我将以下内容添加到抽象测试类中:

// N.b. not setting @Test - so doesn't run all tests twice...
public void runTests(){
  testMyMethod();
  // etc.
}

但是,这不会独立运行每个测试(例如,setUp()在每个测试方法之前运行),因此如果这些合同测试期望每个测试的实现处于特定状态,则会出现问题。(一个具体的例子是测试Iterator接口的实现,其中每个测试方法都可以改变被测试的状态Iterator

有没有更好的方法来做到这一点,也许是利用 JUnit 4 中的特性?

我已经看到有关@RunWith(Suite.class)注释的内容,但这似乎是关于从单个测试类运行多个测试类,并且不允许您将变量传递到正在运行的不同测试类中。可能有一种方法可以使用它 Suite来解决我的问题,但我不确定它是什么......

4

1 回答 1

0

首先,如果您要对抽象测试类进行子类化,则不需要使用Parameterized. 您可以使用Parameterized而不是子类化,但您不太可能同时需要两者。除非您想测试每个实现的多个实例,我将在下面演示!

一种方法是让返回实例的测试只是更多的子类或AbstractAnotherInterfaceTest.

假设你有:

public abstract class AbstractAnotherInterfaceTest {

    private AnotherInterface instance;

    protected AbstractAnotherInterfaceTest(AnotherInterface instance) {
        this.instance = instance;
    }

    @Test
    public void everythingIsOkay() {...}

}

你有:

public class Pony implements AnotherInterface { ... }
public class PonyProducingMyInterface implements MyInterface<Pony> { ... }

你可以写:

@RunWith(Parameterized.class)
public class PonyTest extends AbstractAnotherInterfaceTest {

    @Parameterized.Parameters
    public static Collection<Pony> ponies() {
        return Arrays.asList(
            new Pony(), // base case
            new PonyProducingMyInterface().myMethod() // testing the factory
        );
    }

    public PonyTest(Pony instance) {
        super(pony);
    }

}

诚然,这有点奇怪,因为该new PonyProducingMyInterface().myMethod()案例实际上是对 , 的测试PonyProducingMyInterface,但被归类为AbstractAnotherInterfaceTest.

我能想到的唯一方法会AbstractAnotherInterfaceTest在某些子类中使用测试AbstractMyInterfaceTest是编写一个自定义ParentRunner,它知道如何将实例设置AbstractAnotherInterfaceTest为实例的子类AbstractMyInterfaceTest。您可能希望使其具有通用性,使用注释来指导该过程。

于 2012-07-06T08:28:19.227 回答