Testing asynchronous services with Mockito

by Stefan

Programming asynchronous services can be really challenging. Examples are asynchronous webservices, GWT server calls or event-based systems like widget toolkits. Usually, clients have to pass a callback to the service on which a method is called on success or error containing the data to proceed or an error message.
A typical asynchronous system is your local pizza service:

package cleancodematters;

public class PizzaService {

  public interface PizzaEvent {
    void pizzaAvailable( Pizza pizza );
  }

  public void orderPizza( String name, PizzaEvent event ) {
    // some async processing, calls event on finish
  }
}


When testing this service, the passed pizza instance should be checked. Mockito provides at least two ways to capture the passed argument. First one uses a custom ArgumentMatcher:

package cleancodematters;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.mockito.ArgumentMatcher;

public class PizzaServiceTest {
  
  @Test
  public void testOrderPizzaWithArgumentMatcher() {
    final String pizzaName = "Margarita";
    PizzaService service = new PizzaService();
    PizzaEvent event = mock( PizzaEvent.class );
    
    service.orderPizza( pizzaName, event );
    
    verify( event ).pizzaAvailable( argThat( new ArgumentMatcher<Pizza>() {
      @Override
      public boolean matches( Object argument ) {
        assertEquals( pizzaName, ((Pizza) argument).getName() );
        return true;
      }
    } ) );
  }
}

As a best practice I prefer to always return true in the matches() method and use assert*-methods to check the exact parameters. If something went wrong, the exact line is given in the exception instead of the message, that the argument doesn’t match. This is especially helpful if there is more than one property to compare.

Two things leave a bad taste: The anonymous class makes the test hardly readable. Second, the cast of the argument in the Matcher implementation.
There’s another possibility using the ArgumentCaptor class:

  @Test
  public void testOrderPizzaWithArgumentCaptor() {
    String pizzaName = "Margarita";
    PizzaService service = new PizzaService();
    PizzaEvent event = mock( PizzaEvent.class );
    
    service.orderPizza( pizzaName, event );
    
    ArgumentCaptor<Pizza> captor = ArgumentCaptor.forClass( Pizza.class );
    verify( event ).pizzaAvailable( captor.capture() );
    Pizza capturedPizza = captor.getValue();
    assertEquals( pizzaName, capturedPizza.getName() );
  }

This approach is more compact. However, capturing the arguments still takes 3 lines of code, but can be extracted into a private method.
Creating ArgumentCaptors with generics (e.g. List) require an ugly cast which again produces two warnings.


    @SuppressWarnings({ "rawtypes", "unchecked" })
    ArgumentCaptor<List<Pizza>> captor = ( ArgumentCaptor ) ArgumentCaptor.forClass( List.class );

To workaround this you can let Mockito create the Captor instance:


  @Mock
  ArgumentCaptor<List<Pizza>> captor;
  
  @Before
  public void setup() {
    MockitoAnnotations.initMocks( this );
  }

About these ads

5 Comments to “Testing asynchronous services with Mockito”

  1. You need targeted traffic to your website so why not try some for free? There is a VERY POWERFUL and POPULAR company out there who now lets you try their traffic for 7 days free of charge. I am so glad they opened their traffic system back up to the public! Sign up before it is too late: http://voxseo.com/traffic/

  2. Thanks for the tip, this makes things much cleaner. I did find that I had to use @Captor rather than @Mock, otherwise Mockito displayed an “Invalid use of argument matchers warning”.

  3. Marvelous! Continue the good work. :-D

  4. I see a lot of interesting articles on your blog. You have to spend a lot of time writing, i know how to save you a lot of work, there is a tool that
    creates unique, google friendly articles in couple of minutes, just type in google – k2 unlimited content

  5. I read a lot of interesting posts here. Probably you spend a lot of time writing, i know how
    to save you a lot of time, there is an online tool that creates high quality, SEO friendly
    articles in seconds, just type in google – laranitas free
    content source

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 25 other followers

%d bloggers like this: