How to capture saved value in Java?

Solution 1:

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:

  1. Fetching existing Menu from the repository, finding by uuid
  2. Converting it i.e. updating it from request
  3. Persisting it back in repository using save
  4. 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.

Regarding using ArgumentCaptor, let's suppose your MenuConverter is changing the values of the menu, something like this:

public class MenuConverter {

    public static void convert(MenuRequest request, Menu menu) {
        menu.setName(request.getName() + "_new");
    }

}

then first of all, you should have a different test for MenuConverter that tests this logic, still if you want to test this in the test of MenuServiceImpl itself, then you don't have to use ArgumentCaptor, you can use something like:

@Test
void test_Update() {

// same as above

  verify(existingMockMenu).setName("Menu1_new");
}

This verifies that MenuConverter attempted to update the name of your existingMockMenu