Working with Mockito

This section provides an overview of Mockito. Here is the official Mockito logo:

Working with Mockito

The following topics are covered in this section:

  • Configuring Mockito
  • Stubbing method calls
  • Throwing exceptions
  • Matching method arguments
  • Verifying method calls

Download the latest Mockito binary ZIP folder from the following link and add it to the project dependency. The recommended channel for getting Mockito is Maven (or Gradle), or download it directly from the central Maven repository if you need to get the JAR files manually from either http://central.maven.org/maven2/org/mockito/mockito-all/ or http://central.maven.org/maven2/org/mockito/mockito-core/.

As of April 2014, the latest Mockito version is 1.9.5.

Adding a Mockito dependency

The following steps describe how Mockito JAR files can be added as project dependency:

  1. Extract the JAR files into a folder.
  2. Launch Eclipse.
  3. Create an Eclipse project named 3605OS_Socializing_with_Mockito.
  4. Go to the Libraries tab in the project's build path.
  5. Click on the Add External JARs… button and browse to the Mockito JAR folder.
  6. Select all the JAR files and click OK.

The following code snippet will add the Mockito dependency to a Maven project and download the JAR files from the central Maven repository (http://mvnrepository.com/artifact/org.mockito/mockito-core):

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>1.9.5</version>
  <scope>test</scope>
</dependency>

The following Gradle script snippet will add the Mockito dependency to a Gradle project:

  testCompile 'org.mockito:mockito-core:1.9.5'

Stubbing method calls

This section demonstrates the mock objects with an example. The following jQuery table displays a list of countries:

Stubbing method calls

This special table has numerous controls; you can sort by a column, either in descending or ascending order. The table displays selectable rows per page as a dropdown; you can change the number of records per page — you can choose 10, 15, 20, 30, or 50. The table has a next page, previous page, first page, and last page widget. It has a refresh icon to load the latest dataset.

We need to create a controller class to accept the Ajax call from the jQuery table and return a country list. The Ajax request contains the requested page number, rows per page, sort order, sort column name, and search query. The controller needs to retrieve the country details from a database table and return only filtered countries as an Ajax response.

The following is the Ajax controller class:

@Controller
@Scope("session")
public class AjaxController {
  private final CountryDao countryDao;

  public AjaxController(CountryDao countryDao) {
    this.countryDao = countryDao;
  }

  @RequestMapping(value = "retrieveCountries", method = RequestMethod.POST)
  public @ResponseBody
  JsonDataWrapper<Country> retrieve(HttpServletRequest webRequest) {
    List<Country> countries = new ArrayList<Country  >();
    RetrieveCountryRequest request = RequestBuilder.build(webRequest);
    countries = countryDao.retrieve(request);
    Long startIndex = (request.getPage() - 1) * (request.getRowPerPage());
    int size = countries.size();
    Long endIndex = (startIndex + request.getRowPerPage()) > size ? size: (startIndex + request.getRowPerPage());
    if (startIndex < endIndex) {
      countries = countries.subList(startIndex.intValue(),
      endIndex.intValue());
   }

    JsonDataWrapper<Country> wrapper = new JsonDataWrapper<Country>(request.getPage(), size, countries);

    return wrapper;
  }

}

The retrieve method accepts an HttpServletRequest object and builds a database access request from this object. The following is the request's builder code:

public class RequestBuilder {

  public static RetrieveCountryRequest build(HttpServletRequestwebReq) {
    RetrieveCountryRequest request = new RetrieveCountryRequest();
    request.setPage(getLong(webReq.getParameter("page")));
    request.setRowPerPage(getInt(webReq.getParameter("rp")));
    request.setSortOrder(SortOrder.find(webReq.getParameter("sortorder")));
    request.setSortname(SortColumn.find(webReq.getParameter("sortname")));
    request.setSerachQuery(webReq.getParameter("qtype"));

    return request;
  }

  private static Integer getInt(String val) {
    Integer retVal = null;
    try {
      retVal = Integer.parseInt(val);
    } catch (Exception e) {
    }

  return retVal;
  }

  private static Long getLong(String val) {
    Long retVal = null;
    try {
      retVal = Long.parseLong(val);
    } catch (Exception e) {
    }
    return retVal;
  }
}

Finally, the retrieve method builds a JsonDataWrapper object from the country list and hands it over to the Ajax request as JSON data. The @ResponseBody annotation instructs the JSON response.

To unit test this class, we need to create an HttpServletRequest object, populate it with testable data, and then isolate the countryDao/database access call.

We'll use the Mockito framework to create a mock HttpServletRequest object and isolate the countryDao access call by stubbing the database call.

A mock object can be created with the help of a static method mock(). You need to invoke the Mockito.mock() method or static import Mockito's mock() method. The following is the syntax:

import org.mockito.Mockito;
public class AjaxControllerTest {

  HttpServletRequest request;
  CountryDao countryDao;

  @Before
  public void setUp(){
    request = Mockito.mock(HttpServletRequest.class);
    countryDao = Mockito.mock(CountryDao.class);
  }
}

The following code snippet uses Java's static import construct:

import static org.mockito.Mockito.mock;
public class AjaxControllerTest {

  HttpServletRequest request;
  CountryDao countryDao;

  @Before
  public void setUp(){
    request = mock(HttpServletRequest.class);
    countryDao = mock(CountryDao.class);
  }
}

Tip

Static import in Java allows you to import static members and methods of Java classes and use them as if they are local variables or methods declared in the same class.

There's another way of mocking objects — using the @Mock annotation. But to work with the @Mock annotation, it is necessary to call MockitoAnnotations.initMocks(this) before using the mocks; or use MockitoJUnitRunner as a JUnit runner. We'll cover the annotation in depth in the next chapter. The following example is the syntax of mocking using the @Mock annotation:

import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class AjaxControllerTest {

  private @Mock HttpServletRequest request;
  private @Mock CountryDao countryDao;

  @Before
  public void setUp(){
    MockitoAnnotations.initMocks(this);
  }
}

The following is the syntax of the @Mock annotation using MockitoJUnitRunner:

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

@RunWith(MockitoJUnitRunner.class)
public class AjaxControllerTest {

  private @Mock HttpServletRequest request;
  private @Mock CountryDao countryDao;

  @Before
  public void setUp() {
  }
}

Tip

Before we deep dive into the Mockito world, there are a few things to remember—Mockito cannot mock/spy the following things:

  • Final classes
  • Final methods
  • Enums
  • Static methods
  • Private methods
  • The hashCode() and equals() method
  • Anonymous classes
  • Primitive types

PowerMock has the capability to mock these constructs.

We read about stubs in Chapter 1, Exploring Test Doubles. The stubbing process defines the behavior of a mock method, such as what value should be returned or whether any exception should be thrown when the method is invoked.

The Mockito framework supports stubbing and allows us to return a given value when a specific method is called. It can be done using Mockito.when() along with thenReturn().

The following is the syntax for importing when:

import static org.mockito.Mockito.when;

The following test code stubs the retrieve method for CountryDao and returns an empty list. Finally, the stubbing is verified using the assertTrue method:

@Test
public void retrieves_empty_country_list() throws Exception {
  List<Country> list = new ArrayList<Country>();
  list.add(new Country());
  when(countryDao.retrieve(isA(RetrieveCountryRequest.class))).thenReturn(emptyList);

  assertTrue(countryDao.retrieve(new RetrieveCountryRequest()).size() == 1);
}

The when() method represents the trigger—when to stub it. The following methods are used to represent a trigger action or what to do when the trigger is triggered.

  • thenReturn (a value to be returned): This method returns a given value.
  • thenThrow (a throwable to be thrown): This method throws a given exception.
  • thenAnswer (Answer answer): In this method, unlike returning a hardcoded value, a dynamic, user-defined logic is executed; more like fake test doubles. Answer is an interface. Dynamic code logic is needed to implement the Answer interface.
  • thenCallRealMethod(): This method calls the real method on the mock object/spy.

The thenReturn() method has a variant; it can either return a hardcoded value or can accept variable arguments of hardcoded values. What follows are the three ensuing variants:

  • thenReturn(value)
  • thenReturn(value, values...)
  • thenReturn(value).thenReturn(value2).thenReturn(value3)

The thenReturn(value) variant returns the same hardcoded value for each method call, whereas when(mock.someMethod()).thenReturn(10,5,100) returns the following values:

  • During the first invocation, mock.someMethod() returns 10
  • During the second invocation, mock.someMethod() returns 5
  • During the third invocation, mock.someMethod() returns 100
  • During all the other invocations, mock.someMethod() returns 100

We'll use this style of mocking for HttpServletRequest. The following is the modified test:

@Test
public void retrieves_empty_country_list() throws Exception {
  when(request.getParameter(anyString())).thenReturn("1", "10",SortOrder.ASC.name(), SortColumn.iso.name());

  List<Country> countryList = new ArrayList<Country>();
  countryList.add(new Country());

  when(countryDao.retrieve(isA(RetrieveCountryRequest.class))).thenReturn(countryList);
  JsonDataWrapper<Country> response = ajaxController.retrieve(request);

  assertEquals(1, response.getPage());
  assertEquals(1, response.getTotal());
  assertEquals(1, response.getRows().size());

}

The RequestBuilder class calls the getParameter() method of HttpServletRequest to fetch the request parameters. Sequentially, it calls webReq.getParameter("page"), webReq.getParameter("rp"), webReq.getParameter("sortorder"), and webReq.getParameter("sortname").

In the test method, we stubbed the getParameter call with a variable argument thenReturn style.

We used two Mockito matchers, namely, anyString and isA. The anyString() matcher is used to stub the getParameter method. The getParameter method accepts a string argument, such as webReq.getParameter("page"). The anyString matcher is used as a generic argument matcher. This means, no matter what value is passed to the getParameter method, it will return a hardcoded value.

The isA matcher is used to stub the retrieve method of CountryDao to get the following:

  • If the retrieve method is called with a RetrieveCountryRequest object, it will return the country list

In the next section, we'll discuss argument matchers.

Throwing exceptions

Unit tests are not meant only for happy path testing. We should test our code for failure conditions as well. Mockito provides an API to raise errors during testing. Suppose we are testing a flow where we compute some value and then send it to a printer; if the printer is not configured or a network error occurs or a page is not loaded, the system throws an exception. We can test this using Mockito's exception APIs.

How do we test exceptional conditions such as database access failure?

For this, Mockito provides a thenThrow(Throwable)method. This method tells the Mockito framework to throw a throwable (could be exception or error) when the stubbed method is invoked.

JUnit 4.0 provides a way to test exceptions using @Test(expected=<exception>).

We'll stub the countryDao access call to throw an exception and assert the exception using @Test(execpted=). If the test doesn't throw any exception, it will fail:

@Test(expected=RuntimeException.class)
public void when_system_throws_exception() {
  when(request.getParameter(anyString())).thenReturn("1", "10", SortOrder.DESC.name(), SortColumn.iso.name());

  when(countryDao.retrieve(isA(RetrieveCountryRequest.class))).    thenThrow(new RuntimeException("Database failure"));

  JsonDataWrapper<Country> response = ajaxController.retrieve(request);
}

To throw an exception from a void method, use the following code syntax:

doThrow(exception).when(mock).voidmethod(arguments);

Checking and throwing RuntimeException is not recommended. Instead, we can use a specific exception in production code. In JUint 4, there exists an ExpectedException rule API for exception handling.

Using argument matchers

The argument matcher plays a key role in mocking. Mock objects return expected values, but when they need to return different values for different arguments, the argument matcher comes into play.

Suppose we have a method that takes a cricket player's name as an input and returns the number of runs as an output. We want to stub it and return 100 for the player Sachin and 10 for xyz. We have to use the argument matcher to stub this.

Mockito returns expected values when a method is stubbed. If the method takes arguments, the argument must match during the execution. For example, the getValue(int someValue) method is stubbed in the following way:

when(mockObject.getValue(1)).thenReturn(expected value);

Here, the getValue method is called with mockObject.getValue(100). The parameter doesn't match (it is expected that the method will be called with 1, but at runtime it encounters 100), so the mock object fails to return the expected value. It will return the default value of the return type. If the return type is int or short or long, it returns 0 for wrapper types such as integer and long. If it returns NULL for Boolean, it'll return false if the object is null and so on.

Mockito verifies argument values in natural Java style by using an object's equals() method. Sometimes, we use argument matchers when extra flexibility is required. Mockito provides built-in matchers, such as anyInt(), anyDouble(), anyString(), anyList(), and anyCollection(). More built-in matchers and examples of custom argument matchers / hamcrest matchers can be found at the following link:

https://github.com/mockito/mockito/blob/master/src/org/mockito/Matchers.java

Note

Examples of other matchers are isA(java.lang.Class<T> clazz), any(java.lang.Class<T> clazz), and eq(T) or eq(primitive value).

The isA matcher checks whether the passed object is an instance of the class type passed in the isA argument. The any(T) matcher also works in the same way.

Working with wildcard matchers

A test invokes a method on a code under test. When the invoked method creates a new object and passes that to a mock object, the test method doesn't have the reference of that new object. So the test cannot stub the mock method with a specific value, as the value is not available to the test method. In this context, we use the wildcard matchers.

In the following code snippet, an object is passed to a method and then a request object is created and passed to a service. Now, if we call someMethod from a test and service is a mocked object, we cannot stub callMethod from a test with a specific request, as the request object is local to someMethod.

public void someMethod(Object obj){
  Request req = new Request();
  Req.setValue(obj);
  Response resp = service.callMethod(req);
}

In our jQuery example, we create a mock HttpServletRequest object and pass it to AjaxController. We have the control to stub the HttpServletRequest object, but inside the retrieve method, AjaxController creates a new instance of RetrieveCountryRequest and passes it to CountryDao. We don't have any control over the new instance of RetrieveCountryRequest, so we used a wildcard matcher isA() to stub the retrieve method of CountryDao.

Tip

While using argument matchers, all arguments have to be provided by matchers.

We're passing three arguments, and all of them are passed using matchers in the following manner:

verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));

The following example will fail because the first and the third argument are not passed using a matcher:

verify(mock).someMethod(1, anyString(), "third argument");

Working with a custom ArgumentMatcher class

The ArgumentMatcher class allows us to create our own custom argument matchers. The ArgumentMatcher class is a hamcrest matcher with the predefined describeTo() method. Use the Matchers.argThat(org.hamcrest.Matcher) method and pass an instance of the hamcrest matcher. Hamcrest provides a utility matcher class, org.hamcrest.CoreMatchers. A few utility methods for CoreMatchers include allOf, anyOf, both, either, describedAs, everyItem, is, isA, anything, hasItem, hasItems, equalTo, any, instanceOf, not, nullValue, notNullValue, sameInstance, and theInstance. It also includes a few string methods such as startsWith, endsWith, and containsString. All these methods return a matcher.

Look at the usage of assertThat and explore the utility methods. The following section provides example of matchers. Let's start with equalTo. The equalTo matcher is equivalent to assertEquals.

Comparison matchers – equalTo, is, and not

Create a JUnit test, AssertThatTest.java, and static import org.hamcrest.CoreMatchers.*; in the following manner:

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class AssertThatTest {

  @Test
  public void verify_Matcher() throws Exception {
    int age = 30;
    assertThat(age, equalTo(30));
    assertThat(age, is(30));

    assertThat(age, not(equalTo(33)));
    assertThat(age, is(not(33)));
  }
}

Set the age variable to 30 and then, like assertEquals, call equalTo, which is a matcher; equalTo takes a value. If the matcher value doesn't match the actual value, assertThat throws an AssertionError. Set the age variable value to 29 and rerun the test; the following error will occur:

java.lang.AssertionError: 
Expected: <30>
     but: was <29>
  at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
  at org.junit.Assert.assertThat(Assert.java:865)

The is matcher takes a value and behaves similarly to equalTo. The not matcher takes a value or a matcher. In the preceding code, we used assertThat(age, is(not(33)));, which is nothing but age is not 33 and more readable than assert methods.

Compound value matchers – either, both, anyOf, allOf, and not

In this section, we will use the either, both, anyOf, allOf, and not matchers. Add the following test to the AssertThatTest.java JUnit test:

@Test
public void verify_multiple_values() throws Exception {

  double marks = 100.00;
  assertThat(marks, either(is(100.00)).or(is(90.9)));

  assertThat(marks, both(not(99.99)).and(not(60.00)));
  assertThat(marks, anyOf(is(100.00),is(1.00),is(55.00),is(88.00),is(67.8)));

  assertThat(marks, not(anyOf(is(0.00),is(200.00))));

  assertThat(marks, not(allOf(is(1.00),is(100.00), is(30.00))));
}

In the preceding example, a double variable mark is initialized with the value 100.00. This variable value is asserted with an either matcher.

Basically, using either, we can compare two values against an actual/calculated value. If any of them match, the assertion is passed. If none of them match, AssertionError is thrown.

The either(Matcher) takes a matcher and returns a CombinableEitherMatcher class. The CombinableEitherMatcher class has an or(Matcher other) method so that either and or can be combined:

or(Matcher other) is translated as 
return (new CombinableMatcher(first)).or(other);-> finally to 
new CombinableMatcher(new AnyOf(templatedListWith(other)));

Using both, we can compare two values against an actual/calculated value. If neither of them match, the assertion error is thrown. If both of them match, the assertion is passed.

A numeric value, like math score, cannot be equal to both 60 and 80. But we can negate the expression. If the math score is 80, using the both matcher, we can write the expression as assertThat (mathScore , both (not(60)). and(not (90))).

The anyOf matcher is more like either with multiple values. Using anyOf, we can compare multiple values against an actual/calculated value. If any of them match, the assertion is passed. If none of them match, the assertionError is thrown.

The allOf matcher is more like both with multiple values. Using allOf, we can compare multiple values against an actual/calculated value. If none of them match, the assertionError is thrown. Just like both, we can use allOf, along with not, to check that a value doesn't belong to a set.

In the preceding example, using allOf and not, we checked that the score is not 1 or 100 or 30.

We'll create a custom matcher for the jQuery table example.

The CountryDao access call accepts a request and returns a list of countries. The request contains the sort column name and the sort order. We can create a matcher to return the country list sorted in ascending order. The following is a custom matcher:

class SortByISOInAscendingOrderMatcher extends
ArgumentMatcher<RetrieveCountryRequest> {
  @Override
  public boolean matches(Object request) {
    if (request instanceof RetrieveCountryRequest) {
      SortOrder sortOrder = ((RetrieveCountryRequest) request).getSortOrder();
      SortColumn col = ((RetrieveCountryRequest) request).getSortname();

      return SortOrder.ASC.equals(sortOrder) && SortColumn.iso.equals(col);
    }
    return false;
  }
}

The preceding code extends the ArgumentMatcher class and overrides the matches method. The matches method checks the RetrieveCountryRequest request type, gets the SortOrder and SortColumn attributes from the request object, and finally, checks the SortOrder type. If the order is ASC and the column name is ISO, the match happens.

If you pass a RetrieveCountryRequest object with SortOrder DESC or SortColumn ISO3, the matches method returns false and the method is not stubbed. The following test method uses the custom matcher:

@Test
public void countryList_sortedBy_ISO_In_asc_order() {
  when(request.getParameter(anyString())).thenReturn("1", "10",     SortOrder.ASC.name(), SortColumn.iso.name());

  Country argentina = new Country();
  argentina.setIso("AR");
  Country india = new Country();
  india.setIso("IN");
  Country usa = new Country();
  usa.setIso("US");

  List<Country> ascCountryList = new ArrayList<Country>();
  ascCountryList.add(argentina);
  ascCountryList.add(india);
  ascCountryList.add(usa);

  when(countryDao.retrieve(argThat(new SortByISOInAscendingOrderMatcher()))).thenReturn(ascCountryList);

  JsonDataWrapper<Country> response = ajaxController.retrieve(request);
  assertEquals(ascCountryList, response.getRows());
}

We stubbed the HttpServletRequest object to return SortOrder.ASC, populated a list, and stubbed the countryDao access call with argThat(new SortByISOInAscendingOrderMatcher()). If we stub the HttpServletRequest object to return a different sort order or sort column name, the test will fail.

Verifying method calls

To verify a redundant method invocation or if a stubbed method was not called but was important from the test perspective, we should manually verify the invocation. We need to use the static verify method.

Mock objects are used to stub external dependencies. We set an expectation and a mock object returns an expected value. In some conditions, a behavior/method of a mock object should not be invoked, or sometimes we may need to call the method N (a number) times. The verify method verifies the invocation of mock objects. Mockito does not automatically verify all stubbed calls; JMock does this automatically.

If a stubbed behavior should not be called, but is called due to bug in a code, the verify method flags the error (but we have to verify that manually). The void methods don't return a value; verify is very handy to test a void method's behavior (explained later).

The verify() method has an overloaded version, which takes VerificationMode (AtLeast, AtMost, Times, and so on) as an argument. The Times mode is a Mockito framework class of package, org.mockito.internal.verification, and it takes the integer argument, wantedNumberOfInvocations.

If 0 is passed to Times, it infers that the method will not be invoked in the testing path. We can pass 0 to Times(0) to make sure that the sell or buy methods are not invoked. If a negative number is passed to the Times constructor, Mockito throws MockitoException - org.mockito.exceptions.base.MockitoException and shows the Negative value is not allowed here error. The following methods are used in conjunction with verify:

  • times(int wantedNumberOfInvocations): This is invoked exactly N times. If the method is not invoked wantedNumberOfInvocations times, the test fails.
  • never(): This is never called or is called as times(0).
  • atLeastOnce(): This is invoked at least once. It works fine if the method is invoked multiple times, but fails if the method is not invoked.
  • atLeast(int minNumberOfInvocations): This is called at least N times. It works fine if the method is invoked more than minNumberOfInvocations times, but fails if the method is not called minNumberOfInvocations times.
  • atMost(int maxNumberOfInvocations): This is called at the most N times. It fails if the method is called more than minNumberOfInvocations times.
  • only(): This is used to verify that only one method is called on a mock. It fails if any other method is called on the mock object. In our example, if we use verify(request, only()).getParameter(anyString());, the test will fail with the following output:
    Verifying method calls

    The test fails as it doesn't expect multiple calls to the request.getParameter() method.

  • timeout(int millis): This is specified in a time range.

Verifying zero and no-more interactions

The verifyZeroInteractions (object, mocks) method verifies that no interactions happened on the given mocks. The following test code directly calls the verifyZeroInteractions and passes the two mock objects. Since no methods are invoked on the mock objects, the test passes.

@Test public void verify_zero_interaction() {
  verifyZeroInteractions(request,countryDao);
}

This is useful if your code depends on two or more collaborators. For a given input, only one collaborator should handle the request while others should just ignore the request.

The verifyNoMoreInteractions (Object, mocks) method checks if any of the given mocks have any unverified interaction. We can use this method after verifying a mock method to make sure that nothing else was invoked on the mock.

This is generally not a good practice as it makes your tests overly brittle and you end up testing more than just what you care about. The following test code demonstrates the verifyNoMoreInteractions method:

@Test public void verify_nomore_interaction() {
  request.getParameter("page");
  request.getContextPath();

  verify(request).getParameter(anyString());
  //this will fail getContextPath() is not verified
  verifyNoMoreInteractions(request);
}

The following is the JUnit output. The test fails as the getContextPath() method was not verified even though the getParameter() method was verified. So the test considered the getContextPath() method invocation as a coding bug and verifyNoMoreInteractions raised the error.

Verifying zero and no-more interactions

Answering method calls

Stubbed methods return a hardcoded value but cannot return a dynamic on-the-fly result. Mockito framework offers callbacks to compute on-the-fly results.

Mockito allows stubbing with the generic Answer interface; this is a callback. When a stubbed method on a mock object is invoked, the answer(InvocationOnMock invocation) method of the Answer object is called. This Answer object's answer() method returns the actual object. The syntax is similar to thenReturn() and thenThrow():

when(mock.someMethod()).thenAnswer(new Answer() {…});

Alternatively, we can also use the following syntax:

when(mock.someMethod()).then(answer);

The Answer interface is defined as follows:

public interface Answer<T> {
  T answer(InvocationOnMock invocation) throws Throwable;
}

The InvocationOnMock argument is an important part of a callback. It gives you the arguments passed to the method and the mock object as well. The following methods of InvocationOnMock are used to get the arguments and the mock object:

Object[] args = invocation.getArguments();
Object mock = invocation.getMock();

The retrieve method of CountryDao is stubbed. We'll create an answer object to dynamically sort the country list based on the input sort order.

In test class, create a list for storing countries, and in the setUp method, populate the list with countries. The following is the changed test code:

  List<Country> countries;

  @Before
  public void setUp() {
    ajaxController = new AjaxController(countryDao);
    countries = new ArrayList<Country>();
    countries.add(create("Argentina", "AR", "32"));
    countries.add(create("USA", "US", "01"));
    countries.add(create("Brazil", "BR", "05"));
    countries.add(create("India", "IN", "91"));
  }

Write a new Answer class to sort the countries list based on the user input. The following example is the custom Answer class:

class SortAnswer implements Answer<Object> {
  @Override
  public Object answer(InvocationOnMock invocation) throws Throwable {
    RetrieveCountryRequest request = (RetrieveCountryRequest) invocation.getArguments()[0];
    final int order = request.getSortOrder().equals(SortOrder.ASC) ? 1: -1;
    final SortColumn col = request.getSortname();
    Collections.sort(countries, new Comparator<Country>() {
      public int compare(Country arg0, Country arg1) {
        if (SortColumn.countryCode.equals(col))
        return order * arg0.getCountryCode().compareTo(arg1.getCountryCode());

        if (SortColumn.iso.equals(col))
        return order * arg0.getIso().compareTo(arg1.getIso());
        return order * arg0.getName().compareTo(arg1.getName());
      }
    });

    return countries;
  }
}

The answer method gets the request object and sorts the countries list based on the SortOrder and SortColumn attributes. The following test verifies the ascending and descending sorting:

  @Test
  public void sorting_asc_on_iso() {
    when(request.getParameter(anyString())).thenReturn("1", "10", SortOrder.ASC.name(),   SortColumn.iso.name());


    when(countryDao.retrieve(isA(RetrieveCountryRequest.class))).thenAnswer(new SortAnswer());

    JsonDataWrapper<Country> response = ajaxController.retrieve(request);
    assertEquals("AR", response.getRows().get(0).getIso());
    assertEquals("BR", response.getRows().get(1).getIso());
    assertEquals("IN", response.getRows().get(2).getIso());
    assertEquals("US", response.getRows().get(3).getIso());
  }

  @Test
  public void sorting_desc_on_iso() {
    when(request.getParameter(anyString())).thenReturn("1",       "10",SortOrder.DESC.name(), SortColumn.iso.name());

    when(countryDao.retrieve(isA(RetrieveCountryRequest.class))).thenAnswer(new SortAnswer());

    JsonDataWrapper<Country> response = ajaxController.retrieve(request);
    assertEquals("AR", response.getRows().get(3).getIso());
    assertEquals("BR", response.getRows().get(2).getIso());
    assertEquals("IN", response.getRows().get(1).getIso());
    assertEquals("US", response.getRows().get(0).getIso());

  }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.17.27