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.
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.
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.
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 mockedrepository
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.