我正在研究一种方法,可以将其视为另一种已经定义和测试的方法的特化。这是一个示例代码来说明:
public class ProductService {
public void addProduct(Product product) {
//do something
}
public void addSpecialProduct(Product product) {
addProduct(product);
//do something after
}
}
我不想复制addProduct
已经非常复杂的测试。我想要的是当我为addSpecialProduct
定义测试时,我只是确保它在过程中也调用addProduct
。如果这是2个类协作的问题,那么很容易让协作者进行模拟并且只是验证目标方法是否被调用(并在必要时存根)。但是,这两种方法属于同一类。
我现在想的是监视我正在测试的对象,例如:
public void testAddSpecialProduct() {
//set up code
ProductService service = spy(new DefaultProductService());
service.addSpecialProduct(specialProduct);
verify(service).addProduct(specialProduct);
//more tests
}
但是,我想知道这种方法是否会以某种方式违背单元测试的目的。关于此事的一般共识是什么?
答案 0 :(得分:0)
我认为这取决于您希望单元测试的严谨程度。在极端意义上,单元测试应该只测试行为,而不是实现。这意味着您需要复制您的测试(或者采取@chrylis'建议将常用功能抽象给帮助者)。确保调用另一个方法是测试实现。
但实际上,我认为你在实例上监视间谍以确保调用其他经过良好测试的方法的想法是个好主意。以下是我的理由:
1)它简化了您的代码。
2)我立即清楚地知道发生了什么。它告诉我,为其他方法测试的所有东西现在也都是真的,这里有额外的断言。
有一天,您可以修改实现,以便不调用其他方法,这将导致您的单元测试失败,这是人们通常试图通过不测试实现来避免的。但根据我的经验,当行为发生变化时,这样的变化会更加常见。
答案 1 :(得分:0)
您可以考虑重构代码。使用策略模式实际实现添加产品和特殊产品的功能。
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
将有2个实现。一个人做了原始ProductService.addProduct
实现中发生的事情。第二个实现将委托给第一个实现,然后执行所需的额外工作。因此,您可以单独测试每个策略。第二个策略实现只是第一个实现的装饰器。