使用相同的测试测试多个接口实现 - JUnit4

时间:2012-06-18 09:31:38

标签: junit4

我想为不同的接口实现运行相同的JUnit测试。我找到了一个很好的解决方案,使用 @Parameter 选项:

public class InterfaceTest{

  MyInterface interface;

  public InterfaceTest(MyInterface interface) {
    this.interface = interface;
  }

  @Parameters
  public static Collection<Object[]> getParameters()
  {
    return Arrays.asList(new Object[][] {
      { new GoodInterfaceImpl() },
      { new AnotherInterfaceImpl() }
    });
  }
}

此测试将运行两次,首先使用 GoodInterfaceImpl ,然后使用 AnotherInterfaceImpl 类。但问题是我需要大多数测试用例是一个新对象。一个简化的例子:

@Test
public void isEmptyTest(){
   assertTrue(interface.isEmpty());
}

@Test
public void insertTest(){
   interface.insert(new Object());
   assertFalse(interface.isEmpty());
}

如果在 insertTest 之后运行 isEmptyTest ,则会失败。

是否可以选择使用新的实现实例自动运行每个测试用例?

BTW:为接口实现 clear() reset() - 方法实际上不是一个选项,因为我不需要它在生产代码中。

4 个答案:

答案 0 :(得分:5)

以下是使用模板方法模式的另一种方法:

面向接口的测试进入基类:

public abstract class MyInterfaceTest {

    private MyInterface myInterface;

    protected abstract MyInterface makeContractSubject();

    @Before
    public void setUp() {
        myInterface = makeContractSubject();
    }

    @Test
    public void isEmptyTest(){
        assertTrue(myInterface.isEmpty());
    }

    @Test
    public void insertTest(){
        myInterface.insert(new Object());
        assertFalse(myInterface.isEmpty());
    }
}

对于每个具体类,定义一个具体的测试类:

public class GoodInterfaceImplTest extends MyInterfaceTest {

    @Override
    protected MyInterface makeContractSubject() {
        // initialize new GoodInterfaceImpl
        // insert proper stubs
        return ...;
    }

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

与@Parameter相比,稍微优点是您获得了测试失败时报告的具体测试类的名称,因此您可以立即知道哪个实现失败。

顺便说一下,为了使这种方法完全可行,接口的设计必须允许仅通过接口方法进行测试。这意味着基于状态的测试 - 您无法验证基础测试类中的模拟。如果您需要在特定于实现的测试中验证模拟,那么这些测试必须进入具体的测试类。

答案 1 :(得分:4)

创建工厂接口和实现,如果您在生产中不需要这样的东西,可能只在测试层次结构中创建,并使getParameters()返回工厂列表。

然后,您可以使用@Before带注释的方法调用工厂,以便为每个测试方法运行获取正在测试的实际类的新实例。

答案 2 :(得分:1)

以防有人到达这里(就像我一样),在.net中寻找测试同一界面的多个实现,你可以看到我在其中一个项目中使用的方法之一here

以下是我们所遵循的内容

通过设置环境变量,使用vstest.console运行相同的测试项目dll两次。在测试中,(在程序集初始化或测试初始化​​中)根据环境变量值将适当的实现注册到IoC容器中。

答案 3 :(得分:0)

在Junit 5中你可以这样做:

@ParameterizedTest
@MethodSource("myInterfaceProvider")
void test(MyInterface myInterface) {}

static Stream<MyInterface> myInterfaceProvider() {
   return Stream.of(new ImplA(), new ImplB());
}

interface MyInterface {}

static class ImplA implements MyInterface {}

static class ImplB implements MyInterface {}