我正在尝试测试服务类(负责调用存储库层并在需要时执行一些操作),基本上,这是我正在尝试测试的类
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);
,如何在“deleteById”方法上模拟对“findById”的调用
它仍然调用方法所以我需要模拟对存储库的调用以便通过id查找,即使我已经测试了方法findById。
答案 0 :(得分:7)
这不一定是一种气味,你可以像这样部分模仿BroadcastReceiver receiveSMS = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
String smsBody = intent.getStringExtra("sms");
String pin = smsBody.replace(getResources().getString(R.string.your_extra_text), "").trim();
editText_confirm_pin.setText(pin);
if (validatePin(pin))
// go through the app
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
:
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
,为其提供一个真实的存储库,并在底层存储上使用真实的调用来断言每个方法的实际结果另外,我猜想将存储库注入域对象的想法是故意使用"活动记录"模式,您的实体知道如何自己CRUD。 可以被视为代码气味;它违反了SRP并且可能被认为是一个不好的关注点,因为域对象知道两件事:它自己的状态以及如何坚持自己。
答案 1 :(得分:2)
您希望您的测试设置和测试代码尽可能“简约”。从这个意义上说,另一个答案是正确的说:如果你可以在没有特殊设置的情况下测试deleteById()
,那就去做吧。
事实证明findById()
本身就是一个需要大量测试设置的“巨大”事物 - 然后我宁愿退一步考虑将此方法的内容放入 distinct 类 - 某种CarIdentityService
。
含义:当我们开始使 test 代码更复杂时,通常更好的答案是退后一步并改变我们的生产代码的设计。在您的情况下,您可能希望将整个findById()
代码推送到一个不同的类中 - 现在您只需模拟 CarService
类中的查找器对象。
仅供记录:CarIdentityService
可以是CarService
的本地或内部类。但引入它可能会让您简化实施并避免陷入间谍业务。