2012-06-18 68 views
8

我想运行不同的接口实现相同的JUnit测试。我发现与@Parameter选项很好的解决方案:用同样的测试测试多接口的实现 - JUnit4

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()); 
} 

如果isEmptyTestinsertTest后运行失败。

是否有与实施的新实例自动运行测试用例每一个选项?

BTW:实现明确的()复位() - 方法的接口是不是一个真正的选择,因为我不需要它的生产代码。

+0

我建议寻找到依赖注入。这里是一篇关于如何使用它来完成你正在寻找的东西的小文章 http://www.javaranch.com/journal/200709/dependency-injection-unit-testing.html –

+0

感谢您的快速回答!但是这篇文章描述了如何打破一个接口的依赖关系。我想测试接口(而不是使用接口的类,或者根据文章说话:我想测试远程服务器场(分别是引擎)而不是农场servlet [分别是汽车])。 –

回答

4

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

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

+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微弱优势是在测试失败时,你得到报告的具体测试类的名称,让你马上知道哪个实现失败。

顺便说一下,为了这个方法在所有的工作中,接口必须在某种程度上允许测试仅由接口方法设计。这意味着基于状态的测试 - 您无法在基本测试类中验证模拟。如果您需要在特定于实现的测试中验证模拟,那么这些测试必须进入具体测试类。

+0

+1另一个好方法:)但是关于类名称,现在有可能(JUnit> = 4.11)给测试赋予不同的名称,尽管它不是很方便使用 - > http://stackoverflow.com/questions/650894/changing-names-of-parameterized-tests(s。最高评分的答案,而不是接受的)。不过,我喜欢你的解决方案,因为你可以将实现特定的测试添加到派生测试类中。有些事情我需要额外的课程。 –

1

万一有人达到这里(像我一样),寻找.NET测试相同接口的多个实现,你可以看到,我用在项目中的一个方法之一here

以下就是我们在短期

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

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 {}