2016-04-03 47 views
4

我的问题是关于测试一个实现了很多接口的类。例如,我有这个类:我们如何测试一个类实现了很多接口?

public class ServiceControllerImpl extends ServiceController implements IDataChanged, IEventChanged { 

} 

现在有两种测试方法。首先是对具体课程直接进行测试。这意味着对象类型是具体类而不是接口。

public class ServiceControllerImplTest { 
    ServiceControllerImpl instance; 
    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     // you can bring this instance anywhere 
    } 
} 

第二种方法是仅在接口上进行测试。我们必须将此对象转换为它实现的所有接口。

public class ServiceControllerImplTest { 
    ServiceController instance;  // use interface here 
    IDataChanged dataChangeListener; 

    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     dataChangeListener = (IDataChanged) instance; 
     // instance and dataChangeListener "look like" two different object. 
    } 
} 

我倾向于第二种方案,因为也许在将来,我们可以改变它实现了与其他对象的接口,因此,使用具体类可能会导致在未来的测试失败。我不知道这个问题的最佳做法。

谢谢:)

+2

对于测试您在接口类型上测试的接口。所以你的第二个解决方案基本上就是要走的路。 – JayC667

+1

我确定上面的评论给出了答案,但你的问题需要澄清一点。当你写'dataChangeListener =(IDataChanged)dataChangeListener;'你的意思是'dataChangeListener =(IDataChanged)实例;',对吧? –

+0

@DaveSchweisguth是的。我编辑过。非常感谢。 – hqt

回答

1

我更喜欢第二个解决方案,因为在现实中,也许在将来,我们可以改变它实现了与其他对象的接口,让使用武力具体的课程可能会导致未来的失败测试。

我想它会导致失败的测试无论如何,因为你通常测试的断言是真实的还是错误的。问题是:这些测试是否适用于任何IDataChanged或这些声明是否仅适用于ServiceControllerImpl

如果断言只适用于ServiceControllerImpl不要紧,如果你使用IDataChanged而不是ServiceControllerImpl,因为当你使用其他IDataChanged对象必须编辑测试 - 不同的断言。如果使用其他对象,测试将失败。

你设置单元测试的方式本身给你一个答案。单元测试通常单独测试一个类。这意味着你嘲笑环境。但是嘲笑环境意味着你知道你测试的类的依赖关系,这是实现细节。所以你的测试是在实现的基础上写的,而不仅仅是接口。

可以编写只测试抽象api的测试 - 就像一个接口一样。但是这通常意味着你的测试也是抽象的。例如。

public abstract class SetTest { 

    @Test 
    public void addAlreadyExistentObject(){ 
     Set<String> setUnderTest = createSetUnderTest(); 
     Assert.assertTrue(setUnderTest.isEmpty()); 

     boolean setChanged = setUnderTest.add("Hello"); 
     Assert.assertTrue(setChanged); 

     setChanged = setUnderTest.add("Hello"); 
     Assert.assertFalse(setChanged); 

     Assert.assertEquals(setUnderTest.size(), 1); 

    } 

    protected abstract Set<String> createSetUnderTest(); 

} 

然后,您可以扩展这些抽象测试来测试具体类的API。例如。

public class HashSetTest extends SetTest { 

    @Override 
    protected Set<String> createSetUnderTest() { 
     return new HashSet<String>(); 
    } 
} 

在这种情况下,您可以替换实现,并且测试必须保持绿色。

但是,这里是另一个抽象api的例子,当替换被测对象时没有任何意义。 如何为所有Runnable s写一个测试?

public class RunnableTest { 

    @Test 
    public void run(){ 
     Runnable runnable = ...; 

     // What to test here? 
     // run is invoked without throwing any runtime exceptions? 
     runnable.run(); 

    } 
} 

正如你可以看到它没有意义在某些情况下的方式来编写测试,这样就可以轻松地更换被测对象。

如果api像Set api定义了一个具体的状态处理,你可以编写抽象测试来测试这个。

1

JayC667已经正确地回答,最好通过它的超类型(S)中的那些类型定义的方法测试,是指一类。但是我会改变你这样做一点,以避免铸造方式:

public class ServiceControllerImplTest { 
    ServiceController controller; 
    IDataChanged dataChangeListener; 

    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     controller = instance; 
     dataChangeListener = instance; 
    } 
} 
相关问题