Affichage des articles dont le libellé est java. Afficher tous les articles
Affichage des articles dont le libellé est java. Afficher tous les articles

dimanche 5 janvier 2014

Mockito in the trenches

I used EasyMock framework for three years, before starting to use Mockito two years ago and I'm now really happy with this framework.

However, it provides some features I never used, and for some features it provides several ways to write your tests. For example you have two ways to create your mocks and two ways to write your expectations.

So, in this article I will present every feature I use, and how I choose to write my Mockito tests.

Our example

Let's start with a simple example, then we will go deeper into the framework.

The class we want to test is a class managing accounts, AccountService, with a single dependency, its repository : AccountRepository. For the moment, AccountService has only one method :

public class AccountService {
  @Inject
  private AccountRepository accountRepository;

  public Account getAccountByLogin(String login) {
    try {
      return accountRepository.findAccount(login);
    } catch (EntityNotFoundException enfe) {
      return null;
    }
  }
}

How can we test that with Mockito?

Mocks creation


The first thing you have to do is to create your class of test and create your mocks. I recommend to use the Mockito annotations and the Junit runner as it is more elegant and concise :

@RunWith(MockitoJUnitRunner.class)
public class AccountServiceTest {
  @InjectMocks
  private AccountService accountService;

  @Mock
  private AccountRepository accountRepository;
}

As you can see, you don't need a @Before method and you don't have to instantiate your objects. All is done automatically by the framework. To inject the mocks in the class to test, Mockito tries to do that using firstly the object constructor, then the object setters or finally the object properties.

doReturn and verify


Now let's test the method getAccountByLogin and the case where an account already exists.

  private static final String LOGIN = "login";
  private static final String PASSWORD = "password";

  @Test
  public void getAccountByLogin_withExistingAccount_shouldReturnTheAccount() 
    throws Exception {
    // Given
    Account existingAccount = new Account(LOGIN, PASSWORD);
    doReturn(existingAccount).when(accountRepository).findAccount(LOGIN);

    // When
    Account result = accountService.getAccountByLogin(LOGIN);

    // Then
    assertEquals(existingAccount, result);
    verify(accountRepository).findAccount(LOGIN);
    verifyNoMoreInteractions(accountRepository);
  }

Explanations :

  • doReturn allows to override the behavior of the AccountRepository.findAccount method. Here we return an Account object to simulate the case that an account already exists
  • verify(accountRepository).findAccount allows to check that this method has been called
  • verifyNoMoreInteractions method allows to be sure that we didn't call another method on this mock. It is useful in that case because you test that you don't do a useless call on your repository

doThrow

Now let's test the case where the account doesn't exist. In that case the repository throws an EntityNotFoundException :

  @Test
  public void getAccountByLogin_withUnexistingAccount_shouldReturnNull() throws Exception {
    // Given
    doThrow(new EntityNotFoundException()).when(accountRepository).findAccount(LOGIN);

    // When
    Account result = accountService.getAccountByLogin(LOGIN);

    // Then
    assertNull(result);
  }

As we used doReturn before, here we use doThrow method. Easy!

doReturn vs thenReturn, doThrow vs thenThrow

With mockito the following instructions are similar :

  // either :
  doReturn(null).when(accountService).getAccountByLogin(LOGIN);
  // or :  
  when(accountService.getAccountByLogin(LOGIN)).thenReturn(null);

  // either :
  doThrow(new EntityNotFoundException()).when(accountRepository).findAccount(LOGIN);
  // or :
  when(accountRepository.findAccount(LOGIN)).thenThrow(new EntityNotFoundException());

However, in the case you want to test a void method, you can write :

  doThrow(new EntityNotFoundException()).when(accountRepository).deleteAccount(LOGIN);

But you cannot write the following instruction because it doesn't compile :

  when(accountRepository.deleteAccount(LOGIN)).thenThrow(new EntityNotFoundException());

So I recommend to always use the do* methods in order to keep your tests coherent.

Object.equals and argument captor


Now let's add another method which create an account :

  public void createAccount(String login, String password) throws ServiceException {
    Account account = new Account(login, password);
    accountRepository.createAccount(account);
  }

It seems very easy to write this test. Let's do a first try :

  @Test
  public void createAccount_nominalCase_shouldCreateTheAccount() throws Exception {
    // When
    accountService.createAccount(LOGIN, PASSWORD);

    // Then
    verify(accountRepository).createAccount(new Account(LOGIN, PASSWORD));   
    verifyNoMoreInteractions(accountRepository);
  }

But unfortunately the test fails! Why? Because the verify instruction checks that the parameters passed in the createAccount method are the same in the test that in the tested code. However, in that case, the Account object has no equals method.

You may think to add an equals method in the Account object but if you do that only for your unit test, it is really a shame. Hopefully Mockito provides a cleaner way to test this case : the argument captor.

  @Test
  public void createAccount_nominalCase_shouldCreateTheAccount() throws Exception {
    // When
    accountService.createAccount(LOGIN, PASSWORD);

    // Then
    assertThatAccountAsBeenCreated();
    verifyNoMoreInteractions(accountRepository);
  }
  
  private void assertThatAccountAsBeenCreated() {
    ArgumentCaptor argument = ArgumentCaptor.forClass(Account.class);
    verify(accountRepository).createAccount(argument.capture());
    Account createdAccount = argument.getValue();

    assertEquals(LOGIN, createdAccount.getLogin());
    assertEquals(PASSWORD, createdAccount.getPassword());    
  }

With this technic, you can retrieve the object passed in the tested code, then do every assertion you want. Here we just want to be sure that the login and the password are correct.

Partial mocking

Now let's add three lines of code in our createAccount method to check that the account doesn't exist before we create it. To do that, we use the existing method getAccountByLogin :

  public void createAccount(String login, String password) throws ServiceException {
    if (getAccountByLogin(login) != null) {
     throw new ServiceException(String.format("The account %s already exists", login));
    }

    Account account = new Account(login, password);
    accountRepository.createAccount(account);
  }

As you have already tested the getAccountByLogin, you don't want to test it again because our tests could become unmaintainable.

So here you can use the partial mocking. The idea is to mock the call to the getAccountByLogin method within the class you are testing. With Mockito (unlike other mock frameworks) it is very easy to do that. You just have to override your method behavior like if you were using a mock :

  @Test
  public void createAccount_nominalCase_shouldCreateTheAccount() throws Exception {
    // Given
    doReturn(null).when(accountService).getAccountByLogin(LOGIN);

    // When
    accountService.createAccount(LOGIN, PASSWORD);

    // Then
    assertThatAccountAsBeenCreated();
    verifyNoMoreInteractions(accountRepository);
    verify(accountService).getAccountByLogin(LOGIN);
  }

Then you just have to add the @Spy annotation on the declaration of your tested object :

  @InjectMocks
  @Spy
  private AccountService accountService;

And it works!

Conclusion

I think I covered every feature of Mockito I use every day. Don't hesitate to ping me if I forgot something important. Anyway, I hope this tutorial helped you to have a better understanding of this great framework!

The whole code, with more cases and tests, is available on my github account.

Also, don't hesitate to consult my recommendations to write maintainable unit tests.

Cheers!


lundi 1 juillet 2013

Why it is faster to write unit tests?

"We don't have the time to write unit tests", "we write the unit tests because it is mentioned in the definition of done", "we write the unit tests at the end of the sprint"... How many times did you hear or maybe say that?

The purpose of this thread is to prove that writing unit tests, particularly before testing in runtime, can help you to be more productive and efficient. To begin, let's compare the development process with and without unit tests.

Without unit tests

How a developer works without unit tests?
  1. Development phase
    • Write the entire code of the feature
  2. Runtime test phase
    1. Constat a bug
    2. Analyse where the bug comes from
    3. Fix the bug
    4. Test if the correction is correct
    5. Continue the test phase until all tests are correct

With unit tests

Now, how a developer works with unit tests?
  1. Development phase
    1. Write a unit test
    2. Write the corresponding code
    3. Write another unit test until the feature is completely developed
  2. Runtime test phase
    1. Constat a bug
    2. Analyse where the bug comes from
    3. Write a unit test reproducing the bug
    4. Fix the bug
    5. Test if the correction is correct
    6. Continue the test phase until all tests are correct

Runtime test phase is expensive

The runtime test phase (with or without unit tests) takes a lot of time for several reasons :
  • For each test, you have to prepare a set of data, even for the margin cases
  • You have to launch your application
  • You have to play your test and maybe find a bug
  • For each bug, you have to find where to fix the bug, possibly using a debugger
  • Then, you have to fix your code
  • Finally, you test again to be sure that your fix is correct. For that, of course, you have to prepare a new set of data

Runtime test phase is longer without unit tests

With unit tests, you can be sure to find most of the bugs directly during the development phase. Of course there are still some bugs but less than if you write no unit tests at all.

So if you have more bugs without unit tests, the runtime test will be longer.

Now, how can be sure without unit tests that a bug fix hasn't broke a functional case you have already test? Are you sure all your code is still working? Maybe you should restart the runtime test phase from the beginning? And what about refactoring your code?

With unit tests, you can be very confident to haven't broke anything because all the tests you have already written can prove you that. Plus, you won't be afraid to do refactoring in order to have a cleaner and more comprehensible code, what will help you to work more efficiently during the next developments.

Conclusion

Of course it is faster to write a code without doing units tests. But how much extra time do you spend testing in runtime or fixing bugs in production?

Less bugs also mean less stress and more time to work on interesting things.

In bonus, you do more code and less functional tests. That's cool, coding is what you are good for!

What about integration tests?

An answer to resolve the cost of the manual tests are the integration tests. Do you still need to do unit tests with integration tests? It is enough to do only unit tests? It is a very interesting question I will try to answer in another thread. But yes, unit tests and integration tests are complementary.

samedi 29 juin 2013

How to test dates in java unit tests?

Testing dates in unit tests is not always an easy stuff. Take a look to the following method, I will then explain you what is the main problem you can encounter.

public class UserService {
  @Inject
  private UserEventDao userEventDao;

  @Inject
  private DateUtility dateUtility;

  public void createCreationUserEvent(User user) {
    UserEvent event = new UserEvent();
    event.setUser(user);
    event.setUserEventType(UserEventType.CREATION);
    event.setEventDate(new Date());
    userEventDao.create(event);
  }
}

To test this method, you have to check that the UserEvent object passed to the UserEventDao.create method is correctly filled. For that you can use a mock framework like Mockito and write the following test :

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
  @InjectMocks
  private UserService userService;

  @Mock
  private UserEventDao userEventDao;

  @Test
  public void createCreationUserEvent_withCorrectParameters_shouldCreateAnEvent() {
    // Given
    User user = new User();

    // When
    userService.createCreationUserEvent(user);

    // Then
    UserEvent expectedUserEvent = new UserEvent();
    expectedUserEvent.setUser(user);
    expectedUserEvent.setUserEventType(UserEventType.CREATION);
    expectedUserEvent.setEventDate(new Date());

    verify(userEventDao).create(expectedUserEvent);
    verifyNoMoreInteractions(userEventDao);
  }
}

The problem is that this test is not in success all the time because the Date object precision is in milliseconds and you can have a little difference between the date created in the method and the date created in the test.

The solution to resolve that is to be sure to manipulate the same Date object between the method and your test. Of course you could add a Date argument in your createCreationUserEvent method but this would just move our problem to the calling method.

I recommend you two solutions to do that : the first one is to use PowerMock and the second one is to create a DateUtility class.

Solution 1 : Using PowerMock

PowerMock is a mock framework allowing you to mock what cannot be mocked by others frameworks : static method calls, private methods, object constructions etc. To do that, Powermock manipulates the bytecode of the class to test.

So in our example, it can mock the new Date() call :
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest {

  @InjectMocks
  private UserService userService;

  @Mock
  private UserEventDao userEventDao;

  @Test
  public void createCreationUserEvent_withCorrectParameters_shouldCreateAnEvent()
  throws Exception {
    // Given
    User user = new User();
    Date eventDate = new Date();
    whenNew(Date.class).withNoArguments().thenReturn(eventDate);

    // When
    userService.createCreationUserEvent(user);

    // Then
    UserEvent expectedUserEvent = new UserEvent();
    expectedUserEvent.setUser(user);
    expectedUserEvent.setUserEventType(UserEventType.CREATION);
    expectedUserEvent.setEventDate(eventDate);

    verify(userEventDao).create(expectedUserEvent);
    verifyNoMoreInteractions(userEventDao);
  }
}

As you surely noticed, we use the PowerMock runner and a PrepareForTest annotation which indicates to Powermock that the UserService class bytecode must be modified.

You can now be sure that your test will be in success at each execution.

Solution 2 : Creating a date utility class

In this solution, the concept is to delegate the creation of the date to a new class :

public class DateUtility {
  public Date getCurrentDate() {
    return new Date();
  }
}

And to use this class in UserService :

public class UserService {

  @Inject
  private UserEventDao userEventDao;

  @Inject
  private DateUtility dateUtility;
  
  public void createCreationUserEvent(User user) {
    UserEvent event = new UserEvent();
    event.setUser(user);
    event.setUserEventType(UserEventType.CREATION);
    event.setEventDate(dateUtility.getCurrentDate());
    userEventDao.create(event);
  }
}

Then we can mock the call to DateUtility in our unit test :

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

  @InjectMocks
  private UserService userService;

  @Mock
  private UserEventDao userEventDao;
  
  @Mock
  private DateUtility dateUtility;

  @Test
  public void createCreationUserEvent_withCorrectParameters_shouldCreateAnEvent() {
    // Given
    User user = new User();
    Date eventDate = new Date();
    doReturn(eventDate).when(dateUtility).getCurrentDate();

    // When
    userService.createCreationUserEvent(user);

    // Then
    UserEvent expectedUserEvent = new UserEvent();
    expectedUserEvent.setUser(user);
    expectedUserEvent.setUserEventType(UserEventType.CREATION);
    expectedUserEvent.setEventDate(eventDate);

    verify(userEventDao).create(expectedUserEvent);
    verifyNoMoreInteractions(userEventDao);
  }
}

Like in the Powermock solution, you can now be sure that your test will be in success at each execution.

Conclusion : Powermock vs DateUtility

Firstly, these two solutions can be applied to every other case where you have to manipulate dates. It works all the time.

The advantage of the Powermock solution is that you don't have to modify your business code to write a good test. However, the bytecode manipulation done by the framework is expensive in term of execution time : in my environment, this simple test needs about 400 ms to be executed whereas the test with Mockito needs almost 0 ms. On more complicated tests with several static classes mocked, this execution time can be even worst : I already saw entire tests classes executed in almost 8 seconds, which can be very problematic in term of productivity.

Concerning the DateUtility solution,  I think it is elegant to have a class with the responsability to manipulate dates. With that, you shouldn't have any "new Date()" call or Calendar manipulation in other classes. And of course, the main bonus is that you can write a good unit test. I would so recommend you this solution!

I hope you enjoyed this thread and I would be very glad to hear which others tricks do you use to test your dates. Also, I you encounter a case where the DateUtility solution cannot help you, I would love to help you.

jeudi 13 juin 2013

Tips to write maintainable unit tests

Because unit tests are considered by a lot of developers as a waste of time, they make no efforts to write a code of quality. It is perhaps not a problem for the developer to understand his tests while he is developing his feature. But when he needs to modify the feature behavior and therefore his tests several weeks later, he will encounter some difficulties to understand his own tests and it will be expensive to modify them.

However it is easy to write a readable and maintainable unit test. You just have to follow several tips.

Tip #1 : give a comprehensive name to each test

Your unit test name should be comprehensive enough to understand which method you are testing and which case you are testing. To achieve that, three information are mandatory in your method name :
  • the name of the tested method
  • the input parameters of the tested method
  • what is the expected behavior of the tested method
If you respect this rule, it is not mandatory anymore to write other documentation (like javadoc in Java). The method name is comprehensive enough. For example :

 @Test  
 public void filterInvalidUsers_withAnInvalidUser_shouldReturnAnEmptyList() {  
 }   

Ok I understand you can be chocked to see an underscore in the method name. But it is a little trick to improve the visibility of what your test is doing. Moreover you can easily identify if you have forgotten a case using the method listing of your favorite IDE :


Tip #2 : use Given / When / Then template

Every unit test has three sections of instructions :
  • the test preparation
  • the call to the tested method
  • the assertions
In some unit tests, it is not always obvious to find these sections. So a little trick to easily identify them is to comment the beginning of each section. "Given" for the test preparation, "When" for the call to the tested method, and "Then" for the assertions. Doing that for each of yours unit tests give a kind of template easily understandable by every developer. For example :

@Test  
public void filterInvalidUsers_withAnInvalidUser_shouldReturnAnEmptyList() {  
   // Given  
   User user = new User();  
   user.setName("userName");  
   user.setBirthDate(new Date());  
   user.setStatus(-1);

   // When  
   List<User> users = userService.filterInvalidUsers(Arrays.asList(user));       

   // Then  
   assertNotNull(users);  
   assertTrue(users.isEmpty());   
 }   

Tip #3 : use reusable methods for the Given and Then sections 

Even if it is logical to factorize your code, this basic coding principle is not always applied to the unit tests. Some developers prefer to copy & paste an entire unit test, just change the test name and one of the assertions, whereas they could create an utility method used by several tests.

An exemple of factorization of our test method could be :

@Test  
public void filterInvalidUsers_withAnInvalidUser_shouldReturnAnEmptyList() {  
   // Given  
   User user = createUserWithCorrectParameters();  
   user.setStatus(-1);

   // When  
   List<User> users = userService.filterInvalidUsers(Arrays.asList(user));       

   // Then
   assertThatThereIsNoUser(users);     
 } 

private User createUserWithCorrectParameters() {
   User user = new User();  
   user.setName("userName");  
   user.setBirthDate(new Date());  
   user.setStatus(10);
   return user;
}

private void assertThatThereIsNoUser(List<User> users) {
   assertNotNull(users);  
   assertTrue(users.isEmpty()); 
}      

 

Tip #4 :  mock all interactions to other objects

An important principle of the unit tests is to test only the behavior of the tested class, and not the behavior of all the objects used by this class. If you don't respect this principle, you could have impacts on several test classes each time you change the behavior of a single class, which is a waste of time.

To do that you can mock every other objects used by the tested class. Mock an object means simulate his behavior and not do a real call to the object. Great Java librairies allow to do this job, for example Easymock or Mockito. I will do a comparative of these two solutions in another thread.

 

Tip #5 : use partial mocking to have smaller tests 

Imagine you want to add a createUsers method in the same class of the filterInvalidUsers method :

public void createUsers(List<User> users) {
    List validUsers = filterInvalidUsers(users);
    if (! validUsers.isEmpty()) {
        userDao.createUsers(validUsers);
    }
}

You have already written your unit tests on filterInvalidUsers and you don't want to write them again. How can you avoid that? A solution is to use partial mocking. Whereas classic mocking allows you to mock the objects used in your tested class, the partial mocking allows you to mock a method in the class you are testing. So you can simulate the call to the method then verify that the call has been performed. For example, in the createUsers unit tests, you can mock the call to the filterInvalidUsers. In Java, EasyMock and Mockito both allow to do partial mocking.

 

Conclusion

 I hope theses few tips will help you to write more maintainable unit tests. Don't hesitate to share your own techniques by commenting this thread. I would be very glad to share with you.