我正在尝试测试服务类(负责调用存储库层并在需要时进行一些操作),基本上,这是我要测试的类
class CarServiceImpl{
public Car findById(String id){
//call repository layer to find a car
}
public void deleteById(String id){
Car car = this.findById(id);
if(car != null){
//Call repository layer to update the car
}else{
Throw NotFOundException();
}
}
}
您可以看到,我在DeleteByid方法上调用FindbyId方法,所以我的问题是。
在同一类中调用方法真的是代码气味吗?我认为我应该创建一个单独的班级以通过ID找到汽车。
如果我使用
Mockito.when(carServiceImpl.findById("car1")).thenReturn(carModel);
它静止呼叫该方法,所以我需要嘲笑对呼吸器的调用,即使我已经测试了FindbyId。
这不一定是气味,您可以像这样部分模拟Car
:
String carId = "...";
Car car = ...;
CarServiceImpl car = mock(CarServiceImpl.class);
when(car.findById(carId)).thenReturn(car);
when(car.deleteById(carId)).thenCallRealMethod();
但是如果您可以允许deleteById()
执行'真实方法',那么您的测试必须已经具有存储库,在这种情况下让findById()
成为"真实呼叫"很简单,并且可以提高您的质量测试覆盖范围〜没有额外费用。您已经测试了findById()
的事实并不意味着您不应该间接测试它,作为deleteById()
的一部分。
我建议您进行以下任意:
- 单位测试
Car
通过给出模拟的repository
并使用模拟的期望和验证来测试其所有方法 - 功能/接受测试
Car
通过给出一个真实的存储库并在基础存储上使用真实的调用来确定其每种方法的实际结果
在单独的音符上,我猜想将存储库注入域对象的想法是故意使用"主动记录"模式,您的实体知道如何抓住自己。此可以将其视为代码气味;它违反了SRP,可以认为是较差的关注点,因为域对象知道两件事:它自己的状态以及如何坚持自己。
您希望测试设置和测试代码尽可能"简约"。从这个意义上讲,另一个答案是正确的:如果您可以在没有特殊设置的情况下测试deleteById()
,那就去了。
,事实证明, findById()
本身就是一个"巨大"的东西,需要大量的测试设置 - 那么我宁愿退后一步,考虑将此方法的内容放入 dintives 类 - 某种CarIdentityService
。
含义:通常,当我们开始制作 test 代码时,更复杂 - 更好的答案是退后一步并更改生产代码的设计。在您的情况下,您可能需要将整个findById()
代码推入独特的类 - 现在您可以简单地模拟在您的CarService
类中的Finder对象。
仅用于记录:CarIdentityService
可以是CarService
的本地或内部类别。但是介绍它可能使您可以简化实施并避免进入间谍业务。