ip696
ip696

Reputation: 7104

How can I create unit test for this method?

How can I create a unit test for this service:

public class UserService {

    private Map<String, User> userStorage = new HashMap<>();

    public void saveOrUpdate(User user) {
        User userFromStorage = userStorage.get(user.getId());

        if (userFromStorage == null) {
            userStorage.put(user.getId(), user);
        } else {
            userFromStorage.setName(user.getName());
            userStorage.put(userFromStorage.getId(), userFromStorage);
        }
    }
}

How can I check that user creates or update successfully?

I can change void to User and return updated user and create this:

assertEquals(user.getName(), updatedUser.getName())

But what if I can't change method signature? How can I test it?

Upvotes: 0

Views: 873

Answers (2)

Andrei Dragotoniu
Andrei Dragotoniu

Reputation: 6335

I would not mock anything here.

you have a HashMap and a User. To be able to work with them they both need to be publicly accessible.

I am not a Java developer so I will leave the coding aspect to someone else.

I would start by injecting the UserStorage into the class ( in constructor for example ) so you can then use it and you can even change implementations. Use an interface for example so you can have multiple implementations if you need to.

Once you do that, you can use it to retrieve the user from the Service and you can assert against it.

Test 1 : add

  • initialize empty storage
  • create User with ID = 1, Name = Peter
  • call saveOrUpdate with this user
  • retrieve user with ID = 1 from storage
  • Assert it equals the user you put in.

Test 2 : update

  • initialize empty storage
  • create User with ID = 1, Name = Peter
  • call saveOrUpdate with this user
  • update User's name to John
  • call saveOrUpdate with updated User
  • retrieve user with ID = 1 from storage
  • Assert it equals the updated user

add more tests for null user, or any other conditions you want to test. I would not mock this, test the real thing instead.

this doesn't involve changing the method's signature, just the way you inject your storage into the class which can be with an IOC framework, if you use one, or simple DI, so not a big change at all.

Upvotes: 0

daniu
daniu

Reputation: 15018

You mock both the userStorage and the passed User.

@RunWith(MockitoJunitRunner.class)
class UserServiceTest {
    @InjectMocks private UserService sut;
    @Mock private Map<String, User> storage;
    @Test
    public void testUpdate() {
        final String ID = "1";
        // setup user passed to method
        User user = mock(User.class);
        when(user.getId()).thenReturn(ID);
        when(user.getName()).thenReturn("name");
        // setup user already known to service
        User fromStorage = mock(User.class);
        when(fromStorage.getId()).thenReturn(ID);
        when(storage.get(ID)).thenReturn(fromStorage);

        // run method under test
        sut.saveOrUpdate(user);

        // check update was performed and storage updated
        verify(fromStorage).setName("name");
        verify(storage).put(ID, fromStorage);
    }
}

I'll leave the save path to you; it's simpler actually.

Upvotes: 2

Related Questions