Mock a method call that is in the same class i'm testing, is it really code smell?

Luis Miguel :

I'm trying to test a service class (responsible for calling the repository layer and do some operations if needed), basically, this is the class I'm trying to test

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();
      }
  }
}

As you can see I call the findById method on the deleteById method, so my questions are.

  1. is it really code smell to call a method on the same class? I don think I should create a separate class to find a car by id.

  2. how can I mock the call to "findById" on the "deleteById" method, if I use Mockito.when(carServiceImpl.findById("car1")).thenReturn(carModel); it stills call the method so i'll need to mock the call to respository for finding by id too, even when i already tested the method findById.

glytching :

This isn't necessarily a smell and you can partially mock Car like so:

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

CarServiceImpl car = mock(CarServiceImpl.class);
when(car.findById(carId)).thenReturn(car);    
when(car.deleteById(carId)).thenCallRealMethod();

But if you can allow deleteById() to execute the 'real method' then your test must already have a repository in which case letting findById() be a 'real call' is simple and improves the quality of your test coverage at ~no additional cost. The fact that you have already tested findById() doesn't mean that you shouldn't test it again, indirectly, as part of deleteById().

I would suggest that you do either or both of the following:

  • Unit test Car by giving it a mocked repository and using mocked expectations and verifications to test all of its methods
  • Functional/Acceptance test Car by giving it a real repository and using real invocations on the underlying store to assert actual results for each of its methods

On a separate note, I'm guessing the idea of injecting a repository into a domain object is a deliberate use of the "active record" pattern where your entities know how to CRUD themselves. This could be considered a code smell; it breaches the SRP and could be held to be a poor separation of concerns because the domain object knows about two things: its own state and how to persist itself.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=461059&siteId=1