axelhodler

Listen to your tests

Recently I encountered a piece of code that, in effect, although a lot more verbose, did something along the following lines

public void addAllowedOperations(User user) {
  Set<UserOperation> operations =
    securityService.fetchAllowedOperationsFor(user);
  user.setAllowedOperations(operations);
}

All allowed operations for the a user are fetched and added to it.

Suppose we need a User with her allowedOperations in another class and achieve this by reusing the method above. In the Unit Test of the other class we would then be stubbing the method addAllowedOperations to provide us with the User with the allowedOperations already set.

Stubbing methods which return something, using the Mockito BDD syntax, looks as follows

User userStub = new User();
userStub.setAllowedOperations(UserOperation.DELETE_USER,
    UserOperation.BUY_STOCKS);

given(service.addAllowedOperations(user)
  .willReturn(userStub));

Because addAllowedOperations does not return anything and instead mutates the argument user, we can’t use the given willReturn structure above.

We need to use the Mockito Answer feature

willAnswer(invocation -> {
  User userStub = (User) invocation.getArguments()[0];
  userStub.setAllowedOperations(UserOperation.DELETE_USER,
      UserOperation.BUY_STOCKS));
  return null;
}).given(service)
    .addAllowedOperations(userStub);

It does not look as straightforward as given and willReturn anymore. In fact I had to check the documentation to find out the Mockito syntax for this apparent sorcery.

What I’m hinting at is even if we don’t yet know what Side-Effects are or which benefits Immutability brings to the table, you are left with a sense that something is awry here.

Thus by taking into account the added complexity of the test setup a developer might, in the future, opt for a design which is easier to test. Even if the method simply returns the mutated App object instead of void.