java - 我们如何测试一个类是否实现了很多接口(interface)?

标签 java unit-testing testing interface

我的问题是关于测试一个实现了许多接口(interface)的类。例如,我有这个类:

public class ServiceControllerImpl extends ServiceController implements IDataChanged, IEventChanged {

}

现在有两种测试方式。第一种是直接在具体类上进行测试。这意味着对象类型是具体类而不是接口(interface)。

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

第二种方式是只在接口(interface)上进行测试。我们必须将该对象类型转换为它实现的所有接口(interface)。

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

我更喜欢第二种解决方案,因为也许将来我们可以将其实现的接口(interface)更改为其他对象,因此使用具体类可能会导致将来测试失败。我不知道这个问题的最佳实践。

谢谢:)

最佳答案

I prefer second solution because in reality, maybe in future we can change the interface it implements to other objects, so force using concreted class maybe leads to fail test in the future.

我猜它无论如何都会导致测试失败,因为您通常会测试断言是真还是假。问题是:该测试适用于任何 IDataChanged 还是这些断言仅适用于 ServiceControllerImpl

如果断言仅适用于 ServiceControllerImpl,则使用 IDataChanged 而不是 ServiceControllerImpl 并不重要,因为您必须当您使用另一个 IDataChanged 对象时编辑测试 - 不同的断言。如果您使用另一个对象,测试将失败。

您设置单元测试的方式本身会为您提供答案。单元测试通常单独测试一个类。这意味着你模拟了环境。但是模拟环境意味着你知道你测试的类的依赖关系,这是实现细节。因此,您的测试是在实现的基础上编写的,而不仅仅是接口(interface)。

可以编写只测试抽象 api 的测试——比如接口(interface)。但这通常意味着您的测试也是抽象的。例如

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 编写一个测试怎么样?

public class RunnableTest {

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

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

     }
}

如您所见,在某些情况下以一种可以轻松替换被测对象的方式编写测试没有意义。

如果像 Set api 这样的 api 定义了具体的状态处理,您可以编写对此进行测试的抽象测试。

关于java - 我们如何测试一个类是否实现了很多接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36384419/

相关文章:

java - 如何根据条件更改 HttpServlet 的服务器/主机

visual-studio-2010 - Visual Studio 2010 未发现新的单元测试

javascript - 使用 QUnit 测试 Angular.js

testing - 对 Elixir Ecto 验证测试不起作用的原因感到困惑

testing - 关于2012年测试经理的问题

reactjs - mocha/chai 如何测试在 then 或 catch 回调中调用了一个方法

java - 将文本文件放入二维数组

java - 在 Vaadin 中为 CustomComponent 创建监听器

java - 如何在spark(java)中合并两个具有不同架构的 Parquet 文件

php - 为什么模拟的 returnValue 在 phpunit 的拆卸中不起作用?