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
Menufrom the repository, finding byuuid - Converting it i.e. updating it from
request - Persisting it back in repository using
save - Creating a
CommandDTOfrom 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.
