Unit testing 单元测试组合

Unit testing 单元测试组合,unit-testing,testing,composition,Unit Testing,Testing,Composition,我们有一个任务。我们正在创建一个Foo类,从businessloginc的角度来看,它有1个职责。但事实证明,这个步法确实很复杂。它由几个步骤/子任务组成,然后可以用类Bar/Baz responsibility来表示。这些类在Foo类之外没有真正意义,它们不会单独使用。所以他们可能会有一个包范围或类似的东西 因此,假设您的Foo类,代表FooTask成为: public class Foo { private final Bar bar; private final Baz b

我们有一个任务。我们正在创建一个Foo类,从businessloginc的角度来看,它有1个职责。但事实证明,这个步法确实很复杂。它由几个步骤/子任务组成,然后可以用类Bar/Baz responsibility来表示。这些类在Foo类之外没有真正意义,它们不会单独使用。所以他们可能会有一个包范围或类似的东西

因此,假设您的Foo类,代表FooTask成为:

public class Foo {
    private final Bar bar;
    private final Baz baz;

    // all-args constructor

    public ReturnType doFooTask(InputParam input) {
        final SubResult subresult = bar.doBarSubTask(input);
        return baz.doBazSubTask(subresult);
    }
}
现在,你将如何测试它?我看到两种选择,但不知道哪一种更好:

1) 通过Foo的公共API测试类Bar和Baz。 我看到了这种方法的一个主要流程:用于组成对象的子对象越多,测试用例就越多

2) 为类Bar和Baz自己编写完整的测试套件(它们是包私有的,所以只要保持适当的测试包层次结构,我就可以毫无问题地测试它们)


那又怎么样?我应该让我的Foo课程未经测试吗?我是否应该重复我的测试(这导致了我以前的问题-大量的测试用例,更糟糕的是,复制粘贴)?或者,我应该模拟所有依赖项,并断言在调用Foo的方法时调用了模拟中的适当方法?

首先为Bar和Baz编写完整的测试套件

如果Foo真的很琐碎,比如在您的示例中,那么您可能不会为它编写测试。但我不想让可测试代码未经测试,所以我会为其编写测试。如果您确实为Foo编写测试,那么只执行测试Foo所需的操作。单元测试方法通常是为Bar和Baz编写接口,然后对它们进行模拟,然后可以使用一些依赖项注入技术来传递模拟。如果Bar和Baz有其他依赖项,或者试图接触文件系统或与数据库或类似的东西,或者如果它们很复杂并且需要大量的设置,那么这肯定是您想要使用的方法

有些情况下你不需要这样做。如果Bar和Baz相当简单,并且没有外部依赖关系,那么您可以编写一个只使用Bar和Baz实例的Foo测试。您编写的这些测试将围绕确保在Foo中编写的行为能够正确运行为中心,并且您在编写时假设Bar和Baz工作正常,因为您已经用单元测试对它们进行了介绍。您不会编写涵盖大量输入和输出组合的测试,因为您已经对Bar和Baz进行了测试,您只是希望获得Foo的分支覆盖率,并确保它在正确的条件下从Bar向Baz发送正确的信息。如果您模拟了Bar和Baz,那么您将编写相同数量的测试


如果Bar和Baz很复杂,需要大量的设置,或者需要模拟或初始化外部依赖项,那么就模拟它们,然后用模拟测试Foo。另外,如果使用实际对象最终会在单元测试中花费很长时间来运行,那么就模拟它们

是的,我知道什么是嘲弄,什么时候使用,相信我;)无论如何,谢谢你的回复。问题是:我应该自己测试成分还是通过“主要”类测试成分?是的,这主要归结于它们各自的复杂性。因为它们是分离出来的,所以我会编写单独覆盖它们的测试,然后只根据需要使用它们来设置一个Foo对象,这样您就可以编写覆盖Foo中逻辑的测试。