模拟我正在测试的同一个类中的方法调用,它真的是代码味道吗?

Lui*_*uel 7 java junit mockito

我正在尝试测试一个服务类(负责调用存储库层并在需要时执行一些操作),基本上,这是我正在尝试测试的类

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();
      }
  }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我在deleteById方法上调用了findById方法,所以我的问题是.

  1. 在同一个类上调用方法真的是代码味道吗?我不认为我应该创建一个单独的类来通过id找到一辆汽车.

  2. 如何在"deleteById"方法上模拟对"findById"的调用,如果我使用Mockito.when(carServiceImpl.findById("car1")).thenReturn(carModel); 它仍然调用方法,所以我需要模拟对存储库的调用以便通过id查找,即使我已经测试了方法findById .

gly*_*ing 7

这不一定是气味,你可以Car像这样部分嘲笑:

String carId = "...";
Car car = ...;

CarServiceImpl car = mock(CarServiceImpl.class);
when(car.findById(carId)).thenReturn(car);    
when(car.deleteById(carId)).thenCallRealMethod();
Run Code Online (Sandbox Code Playgroud)

但是,如果您可以允许deleteById()执行"真实方法",那么您的测试必须已经拥有一个存储库,在这种情况下,让findById()"真正的呼叫"变得简单,并且无需额外费用即可提高测试覆盖率的质量.您已经测试过的findById()事实并不意味着您不应该间接地再次测试它,作为其中的一部分deleteById().

我建议您执行以下任一或两项操作:

  • 单元测试Car,给它一个模拟repository和使用模拟的期望和验证来测试它的所有方法
  • 功能/验收测试Car,为其提供一个真实的存储库,并在底层存储上使用真实的调用来为每个方法声明实际结果

另外,我猜想将存储库注入域对象的想法是故意使用"活动记录"模式,其中您的实体知道如何自己CRUD.这可以被认为是代码气味; 它违反了SRP并且可能被认为是一个不好的关注点,因为域对象知道两件事:它自己的状态以及如何坚持自己.