11

我想为不同的接口实现运行相同的 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());
}

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

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

顺便说一句:为接口实现clear()reset()方法并不是一个真正的选择,因为我在生产代码中不需要它。

4

4 回答 4

8

这是模板方法模式的另一种方法:

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

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 相比的一个轻微优势是,当测试失败时,您可以获得报告的具体测试类的名称,因此您可以立即知道哪个实现失败了。

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

于 2013-02-23T22:42:24.127 回答
6

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

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

于 2012-06-18T09:52:33.827 回答
1

万一有人到达这里(就像我一样),寻找在.net中测试同一接口的多个实现,您可以看到我在此处的一个项目中使用的一种方法

以下是我们简要介绍的内容

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

于 2015-01-10T08:29:48.540 回答
1

在 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 {}
于 2017-11-05T10:23:09.650 回答