I am trying to create a unit test for the following method:
public CommandDTO update(final MenuRequest request) {
Menu menu = menuRepository.findByUuid(request.getUuid());
MenuConverter.convert(request, menu); // map fields
Menu saved = menuRepository.save(menu);
return CommandDTO.builder().uuid(saved.getUuid()).build();
}
I want to capture saved
parameter as it is not returned from the method using the following unit test:
@RunWith(MockitoJUnitRunner.class)
public class MenuServiceImplTest {
@InjectMocks
private MenuServiceImpl menuService;
@Captor
private ArgumentCaptor<Menu> menuCaptor;
// mocks (code omitted for brevity)
@Test
public void test_Update() {
// ...
CommandDTO result = menuService.update(request);
verify(menuRepository).save(menuCaptor.capture());
final Menu captured = menuCaptor.getValue();
}
}
However, the parameter in menuRepository.save()
is the unsaved parameter, but I need to capture saved
parameter. So, how can I do this? Should I use @Spy
instead of ArgumentCaptor
?
CodePudding user response:
If that is a unit test, then I assume you already mock MenuRepository
.
To properly mock MenuRepository
, you need to define the behavior of menuRepository.findByUuid(request.getUuid())
and menuRepository.save(menu)
.
Once you define menuRepository.findByUuid(request.getUuid())
, you need to create a Menu
instance. All you need to do is, to check if the fields of that menu
are updated properly.
CodePudding user response:
Let's try to break down the functionality of the MenuServiceImpl
's update
method:
public CommandDTO update(final MenuRequest request) {
Menu menu = menuRepository.findByUuid(request.getUuid());
MenuConverter.convert(request, menu); // map fields
Menu saved = menuRepository.save(menu);
return CommandDTO.builder()
.uuid(saved.getUuid())
.build();
}
Here is what this method is doing:
- Fetching existing
Menu
from the repository, finding byuuid
- Converting it i.e. updating it from
request
- Persisting it back in repository using
save
- Creating a
CommandDTO
from saved uuid.
Now, when we write UnitTest for a unit then that means we are testing the working of that unit only.
Here MenuServiceImpl
is not responsible to ensure whether the values were mapped correctly or if the updated value was saved correctly, the only work MenuServiceImpl
performs is to call these dependencies in a particular order and that is all we need to test here.
So, here is a correct test for MenuServiceImpl
's update
method:
@Test
void test_Update() {
MenuRequest request = new MenuRequest("1234");
Menu existingMockMenu = mock(Menu.class);
when(menuRepository.findByUuid("1234")).thenReturn(existingMockMenu);
Menu savedMockMenu = mock(Menu.class);
when(menuRepository.save(existingMockMenu)).thenReturn(savedMockMenu);
menuServiceImpl.update(request);
verify(menuRepository).save(existingMockMenu);
}
If at all you want to test if MenuRepository
is saving the Menu
correctly, you will have to write a new test for MenuRepository
, if this is actually a repository that interacts with the database, then it will be helpful to write DB Integration Test.