Java 如何测试依赖于其他已测试方法的方法?

Java 如何测试依赖于其他已测试方法的方法?,java,unit-testing,mockito,Java,Unit Testing,Mockito,我正在研究一种可以被认为是另一种已经定义和测试过的方法的专门化的方法。下面是一个示例代码来说明: public class ProductService { public void addProduct(Product product) { //do something } public void addSpecialProduct(Product product) { addProduct(product); //do

我正在研究一种可以被认为是另一种已经定义和测试过的方法的专门化的方法。下面是一个示例代码来说明:

public class ProductService {

    public void addProduct(Product product) {
        //do something
    }

    public void addSpecialProduct(Product product) {
        addProduct(product);
        //do something after
    }

}
我不想复制我对
addProduct
的测试,这些测试已经相当复杂了。我想要的是,当我为
addSpecialProduct
定义测试时,我只需确保它在这个过程中也调用
addProduct
。如果这是两个类协作的问题,那么很容易对协作者进行模拟,只需验证是否调用了目标方法(必要时进行存根)。但是,这两个方法属于同一个类

我现在想的是监视我正在测试的对象,比如:

public void testAddSpecialProduct() {
    //set up code
    ProductService service = spy(new DefaultProductService());    
    service.addSpecialProduct(specialProduct);
    verify(service).addProduct(specialProduct);
    //more tests
}

然而,我想知道这种方法是否以某种方式违背了单元测试的目的。在这个问题上,大家的共识是什么?

我认为这取决于您对单元测试的要求有多严格。在极端意义上,单元测试应该只测试行为,而不是实现。这意味着您需要复制您的测试(或者采纳@chrylis的建议,将公共功能抽象出来提供给助手)。确保调用另一个方法是测试实现

然而,在现实中,我认为您监视实例以确保调用另一个经过良好测试的方法是一个好主意。以下是我的理由:

1) 它简化了代码

2) 我马上就明白发生了什么事。它告诉我,已经为另一种方法测试过的所有内容现在也将是真实的,下面是额外的断言


有一天,您可能会修改实现,以便不调用另一个方法,这将导致单元测试失败,这是人们通常试图通过不测试实现来避免的。但根据我的经验,当行为将发生改变时,这样的变化更为常见。

< P>你可以考虑重构你的代码。使用策略模式来实际实现添加产品和特殊产品的功能

public class ProductService {

    @Resource
    private AddProductStrategy normalAddProductStrategy;
    @Resource
    private AddProductStrategy addSpecialProductStrategy;

    public void addProduct(Product product) {
        normalAddProductStrategy.addProduct(product);
    }

    public void addSpecialProduct(Product product) {
        addSpecialProductStrategy.addProduct(product);
    }
}

将有两个
AddProductStrategy
的实现。一种方法就是像您最初的
ProductService.addProduct
实现中那样。第二个实现将委托给第一个实现,然后执行所需的附加工作。因此,您可以分别测试每个策略。第二个策略实现只是第一个实现的装饰器。

您能将
addProduct
方法的断言放在一个测试实用程序方法中,并在多个测试用例之间重用它吗?这个类听起来有点代码味道,最好组合这两个功能(产品和特殊产品)分为两个单独的类(这样您的测试就变得明显和简单)。使用通用的“添加”和“专用添加”可以克服单一的责任。@chrylis这听起来很合理,是的。我忘了我以前做过类似的事情。@kuhajeyan不是真的。想象一下:
addProduct
基本上是一种添加产品的简单服务。
addSpecialProduct
是一种添加产品的服务然后做一些其他事情,比如说触发警报/通知等。您在
addProduct
中测试的所有案例是否也适用于
addSpecialProduct
,或者只是其中的一个子集?