用Java为继承的类编写单元测试

时间:2018-10-24 06:37:04

标签: java unit-testing junit

考虑以下Java中的简单类层次结构

class Foo {
    protected void someMethod(Bar bar) {
        ...
    }

    protected void someOtherMethod(Baz baz) {
        ...
    }
}

class EnhancedFoo extends Foo {
    @Override
    protected void someMethod(Bar bar) {
        ...
    }
}

我现在开始为这两个类编写JUnit单元测试。由于两个类的方法someMethod的协定相同,因此两个类基本上需要完全相同的测试方法(关于someMethod方法),这导致代码重复。对具有多个覆盖方法的更丰富的类层次结构执行此操作,就感觉继承对可测试性不利。

此外,即使someOtherMethod中的方法ExtendedFoo没有被覆盖,我也需要包含ExtendedFoo的相关测试,因为这仍然是合同,并且是扩展的类和单元测试应该测试一下。

在Java中是否还有其他组织层次结构的方法更适合可测试性?是否有一些JUnit构造可以帮助缓解此问题?

3 个答案:

答案 0 :(得分:3)

正如我在评论中提到的那样,我认为测试应与实现分离,并应“用例驱动”。看起来像这样:

interface Foo {
    public void doSomething(...);
}

class DefaultFoo implements Foo { ... }
class EnhancedFoo extends DefaultFoo { ... }

class MyUseCaseTest {

   private Foo foo = new DefaultFoo(...); 

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

class AnotherUseCaseTest {

   private Foo foo = new EnhancedFoo(...); 

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

最好是摆脱继承,但这是一个不同的话题...

答案 1 :(得分:1)

在非常相似的情况下,我们使用的一种方法是也重用est类:

class FooTest {
    @Test
    public void testSomeMethodBar() {
        ...
    }

    @Test
    public void void someOtherMethodBaz(Baz baz) {
        ...
    }
}

并将其扩展为子类测试:

class EnhancedFooTest extends FooTest {
    @Test
    public void testSomeMethodBar() {
        ...
    }
}

JUnit将运行此特定的覆盖测试方法,以及FooTest中的其他默认测试。这样就消除了不必要的重复。

在适当情况下,某些测试类甚至被声明为abstract,并通过具体测试类(具体类的测试)进行扩展。

答案 2 :(得分:0)

引用您的问题和评论

  

据我了解,单元测试假定类和它们的方法   做黑匣子并测试他们的合同。

还有

  

由于方法someMethod的合同对于两个   类,我基本上需要完全相同的测试方法(关于   这两个类的someMethod方法),从而导致代码   重复。

在通用单元测试概念的上下文中,这都是错误的假设,在 TDD 的非常狭窄的上下文中,这可能是正确的假设。您尚未为TDD标记问题,所以我只是在猜测,而TDD就是关于可以接受的的内容,从代码角度来看并不一定非常可靠。

TDD 永远不会停止开发人员编写更全面的单元测试,以满足他/她的需求,而不仅仅是合同。

您必须了解,单元测试是用于确保方法准确性的开发人员工具,并且不将方法视为黑匣子-应该测试合同以及实现细节(代码覆盖率)。 开发人员不应像琐碎的方法(如setter / getter方法)那样盲目编写单元测试。

详细介绍代码覆盖率时,您将发现必须为覆盖所有场景的目标方法编写多种测试方法。

如果以下方法的实现未在类EnhancedFoo中更改,为什么要为此编写单元测试?应该假设父类测试将覆盖它。

protected void someMethod(Bar bar) {
    ...
}

您为要更改或添加的方法编写单元测试,不必担心继承层次结构。

我只是想强调 unit :)

一词的重要性