Archive

Posts Tagged ‘unittest’

How we do unit testing with JUnit and Mockito

Introduction

Recently iPROFS hired some new guys and I have had the pleasure of working closely with them in their first period with us.
It is always nice to get a lot of guestions like ‘How do you things like ……’ and ‘Is there a standard for ……..’
Some of the things we take for granted, required some explanation. One of the areas of our craftsmanship, where we have some de facto standards is Unit testing. Our company always had a focus on quality, so Unit testing is a required basic skill.

We use JUnit and Mockito for Unit testing in all our projects.

This post describes how we do unit testing based upon a basic and simple scenario in a web environment.

Scenario

A user selects a product in order to add them to the shopping cart.

A Unit test should specify a given scenario, invoke the class under test and verify if the class did what it had to do.
I start writing my tests with three lines of comment:

  1. //describe scenario
  2. //perform action
  3. //verify outcome

Similar to the Given, When, Then sentence from behaviour driven development, but changed due to a naming conflict on the word when with Mockito. The exacts words don’t matter as long as it helps set your mind in the right mood.

Writing the unit test

I’ll start by creating the Test-class with some basic components: An instance of the class to test and a test-method to invoke a single method of that instance.


public class ProductSelectorServletTest() {

// Instantiate the class under test.
private ProductSelectorServlet servlet = new ProductSelectorServlet();

private HttpServletRequest request;
private HttpServletResponse response;

public void testAddSelectedProductToShoppingCard() {

/* describe scenario */
// User selected a product and submitted it.

/* perform action */
servlet.doPost(request, response);

 

/* verify outcome */
// The selected product should have been added to the shopping cart.
}

From this point on it’s just some small steps to implement that in the test code.

Describe the scenario in code

We specify the behaviour of the HttpServletRequest in a set of rules how object should behave when they are invoked by the class under test. In order to specify those rules dynamically, those object should be a Mockito mock, so we need to add the @Mock-annotation to the fields, eg: @Mock private HttpServletRequest request
This alone will not get it working, because by default JUnit doesn’t know how to handle @Mock-annotations. In order to have Mockito initialize the annotated fields we need to the JUnit to run this Test-class with Mockito:


@RunWith(MockitoJUnitRunner.class)
public class ProductSelectorServletTest() {
.....
}

Now start translating the scenario in to actual java statements:


/* describe scenario */
when(request.getParameter("productId")).thenReturn("someId");

Oke, that looks oke, but probably the servlet uses some backend service to get the Product based upon it’s id. So we need to add another line:

when(backendService.getProduct("someId")).thenReturn(someProduct);

This adds two new object to be added as Mock’s

@Mock private BackendService backendService;
@Mock private Product someProduct;

This code assumes that the servlet has access to the backendService, so this requires some initialization of our test:

@Before
public void setUp() {
servlet.setBackendService(backendService);
when(request.getSession()).thenReturn(session);
when(session.getAttribute("shoppingCart")).thenReturn(shoppingCart);
}

Those last two line may have been a surprise, but we need to specify that behavior in order for the servlet to use the proper instances, so we can validate that changes made to it. And so we need two additional mocked fields.


@Mock private HttpSession session;
@Mock private ShoppingCart shoppingCart;

Verification in code

Again: Just translate the requirements into java statements:


// The selected product should have been added to the shopping cart.
verify(shoppingCart).addProduct(someProduct);

Adding this verify statement will instruct the mock shoppingCart to fail the test if the specified method is not invoked with the proper arguments. In those case we know exactly what the argument should be, so we can specify it.
In other cases that might not be true and we need to implement a different way to match the argument of the invoked method to something we expect. Mockito provided various Matchers for that purpose, with the ability to write your own.

Practical tips for Eclipse Users

For those of you, whom use Eclipse as their IDE, just like me, some practical tips:

  1. Add the following types to your favorites for code completion: (Java > Editor > Content Assist > Favorites in preferences)
    • org.junit.Assert
    • org.mockito.Matchers
    • org.mockito.Mockito
  2. Install EclEmma as a Java Code Coverage Plugin to determine if you need additional test scenarios for full test coverate.

Entire test class

Combining all code from this article should result in the following Test:

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class ProductSelectorServletTest {

private ProductSelectorServlet servlet = new ProductSelectorServlet();

@Mock private HttpServletRequest request;
@Mock private HttpServletResponse response;
@Mock private HttpSession session;
@Mock private BackendService backendService;
@Mock private Product someProduct;
@Mock private ShoppingCart shoppingCart;

@Before
public void setUp() {
servlet.setBackendService(backendService);
when(request.getSession()).thenReturn(session);
when(session.getAttribute("shoppingCart")).thenReturn(shoppingCart);
}

@Test
public void testAddSelectedProductToShoppingCard() throws ServletException, IOException {
/* describe scenario */
// User selected a product and submitted it.
when(request.getParameter("productId")).thenReturn("someId");
when(backendService.getProduct("someId")).thenReturn(someProduct);

/* perform action */
servlet.service(request, response);

/* verify outcome */
// The selected product should have been added to the shopping cart.
verify(shoppingCart).addProduct(someProduct);

}

 

}

Categories: Java Tags: , ,

JUnit suite with all tests

In my previous blog I showed the use of JUnit categories and found that running them though a suite on which all test classes must be specified is a bit clunky. After a bit of experimenting I found a way to have a single suite that includes all test classes from the classpath, and using this suite in the specific category suites.
Read more…

Categories: Java Tags: , ,

JUnit categories for grouping tests

30/01/2011 1 comment

In your build process you want fast running tests to provide whatever feedback they can very quickly. A way to organize this is to group your tests by distinguishing between the fast unit tests and the slower tests such as integration, performance, and load tests. TestNG already supports this, and now with its 4.8 release JUnit catches up with a feature called Categories.
Read more…

Categories: Java Tags: , ,

HST and mockito sitting on a tree

19/10/2010 3 comments

Unit testing your Hippo Site Toolkit components with mockito is so easy, there really is no excuse to not test your hst components any more.
Say you have a component that retrieves a bean from a node, that code might look like this:

public class AnHstComponent extends BaseHstComponent{
  @Override
  public void doBeforeRender(HstRequest request, HstResponse response) throws HstComponentException {
  HippoBean bean = getContentBean(request);
  if(bean!=null) {
    request.setAttribute("document",bean);
    }
  }
}

All we would want to test here is that the HippoBean is retrieved and put on the request
This is not an integration test, but a unit test. So we don’t need or want any interaction with any real JCR repository.
To prevent this we mock the HstRequest and HstResponse interfaces and stub the getContentBean(HstRequest) method.
The test code would then look like this:

@RunWith(MockitoJUnitRunner.class)
public class AnHstComponentMockitoTest {
  @Mock public HstRequest request;
  @Mock public HstResponse response;
  @Spy public AnHstComponent component = new AnHstComponent();
  @Test
  public void testDocumentOnRequestAfterDoBeforeRender() throws Exception {
    //stub
    doReturn(new HippoDocument()).when(component).getContentBean(request);
    //test
    component.doBeforeRender(request, response);
    //verify
    verify(request).setAttribute(anyString(), any(HippoDocument.class));
  }
}

An explanation of the test code

The request and response interfaces are mocked, we can use these to stub any methods we need and verify any operations on it.
These mocked interfaces are passed on to the doBeforeRender method of our HSTComponent.

Since the getContentBean method is part of the BaseHstComponent, we need to partially mock the AnHstComponent.
This is done using mockito’s @Spy technique, which we can use to stub the getContentBean method.
In mockito stubbing is usually done with the When() method.
During stubbing the getContentBeans method is actually called upon using this technique on our real object. This will generate a null pointer exception.
To work around this you can use the doReturn method, which will prevent the real getContentBean method ever to get called.

It is this easy to create a simple testcase for your HstComponent, now go on an create your own!! :-)

ps. Jeroen Reijn has an example testing hst components with easy mock.

Categories: Hippo, Java Tags: , ,
Follow

Get every new post delivered to your Inbox.