Tuesday, 12 July 2011

Specifying parameters for Mockito unit testing

Recently we faced a problem where we wanted to unit-test a service operation using mock objects for dependencies, but the objective of the test was to ensure the operation correctly instantiated an entity from the parameters so that it was ready to be persisted.


@Transactional
public User registerUser(Map<UIField,String> details) {
  User user = new User();
  List<UIField> identifierTypes = referenceDataService.
    getUserIdentifierTypeList();
  Set<UserDetail> userDetails = new HashSet<UserDetail>();
  Set<UserIdentifier> userIdentifiers = new   
    HashSet<UserIdentifier>();
  for(UIField key :details.keySet()) {   
    if(isIdentifierField(key,identifierTypes)) {            userIdentifiers.add(createUserIdentifier(key,
        details.get(key)));
    } else {
      userDetails.add(createUserDetail(key,details.get(key)));
    }
  }
  user.setUserIdentifiers(userIdentifiers);
  user.setUserDetails(userDetails);
  UserStatus status = referenceDataService.
    getUserStatus("REGISTERED");
  user.setUserStatus(status);
  return userService.createUser(user);
}
Listing 1

As listing 1 shows, the registerUser operation instantiates a User object and populates its properties using the parameters passed to the operation. Now we would like the unit-test to ensure this User instance is correctly constructed and its properties correctly populated so that the userService can persist the user. Listing 2 shows the unit-test.


@Test
public void testRegisterUser() {
//need a map of the data that is being submitted for registration.
  Map<UIField,String> data = new HashMap<UIField,String>();
  addUIField(data,"MSISDN","07987654321");
  addUIField(data,"Firstname","Joe");
  addUIField(data,"Lastname","Bloggs");        
  List<UIField> idFieldList = new ArrayList<UIField>();
  idFieldList.add(createUIField("MSISDN"));
     
  Mockito.when(referenceDataService.getUserIdentifierTypeList()).
    thenReturn(idFieldList);
  UserStatus userStatus = new UserStatus();
  userStatus.setValue("REGISTERED");

  Mockito.when(referenceDataService.getUserStatus("REGISTERED")).
    thenReturn(userStatus);
  registrationService.registerUser(data);            
  ArgumentCaptor<User> argument =
    ArgumentCaptor.forClass(User.class);

  Mockito.verify(userService).createUser(argument.capture());
  User user = argument.getValue();
  Assert.assertNotNull(user);

  Assert.assertEquals(user.getUserStatus().getValue(),"REGISTERED");
  Assert.assertEquals(1, user.getUserIdentifiers().size());
  Assert.assertEquals(2, user.getUserDetails().size());
}
 Listing 2

The userService and referenceDataService are mock objects which get injected into the RegistrationService. The concern was how to retrieve the user instance from the registerUser operation so that it can be inspected. For this, Mockito provides the ArgumentCaptor class and its use is highlighted in bold showing how to retrieve the User instance and then carry out further assertions.

No comments:

Post a Comment