Tutorial: unit testing in Eclipse with moreUnit plugin

Eclipse Kepler, even in the Java EE Developers edition, does not include a good enough support for automatic tests development. Both NetBeans and IntelliJ have superior native support for testing. For example, if you rename one class, Eclipse does not rename its test class.

To overcome such limitations, we need to install a plugin.

In this tutorial, I will describe moreUnit (http://moreunit.sourceforge.net/), a plugin which extends Eclipse testing support. I will not cover moreUnit installation because it is quite standard.

Let’s create a standard ant based Eclipse project. In the example the project name is “EclipseTest” and the main package is “it.gualtierotesta”.
20140522_01
In the package, I’ve created a new Java class named MyClass with the following content:

package it.gualtierotesta;

public class MyClass {

    private String msg;

    public String message() {
        return generateMsg();
     }

    private String generateMsg() {
        return "Hello " + msg;
    }

    public String getMsg() {
        return msg;
     }

    public void setMsg(String msg) {
       this.msg = msg;
    }

}

Very simple. We want now to create a unit test to check the message() method. While in the Java Editor window, you should press Ctrl+R (or, from the contextual menu, MoreUnit –> Jump To Test) to trigger test class creation.

20140522_02
where we can select our preferred unit library. In this tutorial we will use JUnit 4.

Press “Finish” to confirm. Note: Eclipse will eventually ask you to add JUnit library to the project build path.

In the created test class (MyClassTest.java file), add the following contents:

package it.gualtierotesta;

import org.junit.Assert;
import org.junit.Test;

public class MyClassTest {

@Test
 public void showMessage() {
     // given
     MyClass sut = new MyClass();
     sut.setMsg("Gualtiero");
     // when
     String res = sut.message();
     // then
    Assert.assertEquals("", res);
 }

}

Note: sut is system under test.

In the test class window, press Ctrl+R to run the test. Test will fail:
20140522_03This is expected because the Assert.assertEquals check for the wrong result.
Change the Assert line as following:

Assert.assertEquals("Hello Gualtiero", res);

E re-run the test (Ctrl+R). Test will now succeed.
20140522_04
Note: in the test method body I added some comment lines to divide the body instructions in three sections. Given section is where the test texture is prepared, when is the execution of the method under test and the then section marks the results checks instructions (assertions). This is a good habit to make test strategy clearer. It comes from BDD, Behavior Driven Development (http://en.wikipedia.org/wiki/Behavior-driven_development).

 

A nice moreUnit feature is to mark the Java source file icon with a small green rectangle to show that the class has a test class.
20140522_05We have now our test running without failure but still our setup is not correct: test classes should be placed in a different source folder because they should not be packaged and released to the user.

Traditional approach is to have src dir for Java source files and test dir for test classes.

We create now a new folder named “test” under project root:
20140522_06
Then in the Java Build Path section of the project properties we add the new test folder as one of the project source folders:
20140522_07
Finally we configure moreUnit to use the “test” folder as the place to create and look for test classes:
20140522_08
Finally we can move the MyClassTest.java to the test folder (or create it again).

At the end, the project configuration is the following:
20140522_09As shown in this short tutorial, moreUnit plugin simplify a lot test classes handling in Eclipse.

Moreover, moreUnit offers special support for mocking libraries users. The test class creation wizard has additional pages to insert mocking specific instructions in the test class:
20140522_10
In this page, you can select the dependencies you want to mock and moreUnit will add specific mocking instructions. For more info about Mockito, have look here and here.

GDocx 3.0.0 released

GDocx, the fluent interface to the Docx4J library, version 3.0.0 has been released.

What’s new ?

GDocx now uses the latest (3.0.1) Docx4j version.

Other changes includes replacement of Fest Assert with the AssertJ library which is more flexible and powerful.

All files, including source and javadoc can be downloaded from the project home at the https://java.net/projects/gdocx

Tutorial: Using Mockito in an integration test

Even if Mockito (see my previous post) usually helps us to cut all dependencies in our unit tests, it can be useful also in the integration tests where we often want to have all real applications layers.

Let’s assume to have the following Spring controller:

@Controller
public class LandingPageController {
  protected static final String ADMIN_MAIN = "adminMain";
  protected static final String PROVIDER_MAIN = "providerMain";
  protected static final String USER_MAIN = "userMain";
  private UserManager userManager;

  @Autowired
  public void setUserManager(final UserManager pUserManager) {
    this.userManager = pUserManager;
  }

  @RequestMapping(value = "/users")
  public ModelAndView landingPage(final HttpServletRequest request) {
    ModelAndView mav;
    final User user = userManager.getCurrentUser();
    if (user.isAdministrator()) {
      mav = new ModelAndView(new RedirectView(ADMIN_MAIN));
    } else if (utente.isProvider()) {
      mav = new ModelAndView(new RedirectView(PROVIDER_MAIN));
    } else {
      mav = new ModelAndView(new RedirectView(USER_MAIN));
    }
    return mav;
  }
}

The controller redirects the currently logged user to a proper landing page, depending on its role.

The controller could be tested with a unit test, mocking the UserManager and asserting the return values but I decided for a different test approach.

In this case, I want to check if Spring configuration is correct and if the controller method is properly invoked when we access the “/users” url.

In other words, I need an integration test which usually requires that all dependencies are real. In this case, the UserManager is already tested in other tests so it would be better to use an UserManager mock to reduce test effort and execution time.

To create an integration test for a Spring based application, I usually use the following abstract class which defines the Spring configuration to be used for test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
  "classpath:/spring/dispatcher-servlet.xml",
  "classpath:/spring/applicationContext.xml",
  "classpath:/spring/security.xml"})
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@Transactional
public abstract class IntegrationTestCase {
  @Autowired
  protected ApplicationContext applicationContext;
}

 Few comments:

  • we use the Spring specific jUnit runner (SpringJUnit4ClassRunner) to have Spring environment during the test
  • with the @ContextConfiguration annotation we define all Spring configuration files which are relevant for the tests

The integration test for our controller is the following:

public class LandingPageControllerIT extends IntegrationTestCase {

we extend the class from the IntegrationTestCase class so we can inherit all Spring configuration. Note: class (and file) name ends with IT which is the maven default for integration test files. See failsafe plugin documentation for more details.

Important: we cannot use the usual Mockito runner because we are using the Spring one, so we will not use Mockito annotations.

private static final String PAGE = "/users";
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private HandlerAdapter handlerAdapter;
private LandingPageController sut;
private UserManager userManager;

MockHttpServletRequest and MockHttpServletResponse are mocking classes available in the Spring library while the HandlerAdapter is the real one because we need in the setUp method which is the following:

@Before
public void setUp() {
  sut = new LandingPageController();
  userManager = Mockito.mock(UserManager.class);
  sut.setUserManager(userManager);

  request = new MockHttpServletRequest();
  request.setRequestURI(PAGE);
  response = new MockHttpServletResponse();

  handlerAdapter = applicationContext.getBean("methodHandler", HandlerAdapter.class);
  assertThat(handlerAdapter.supports(sut)).isTrue();
}

We create the UserManager mock and inject it in the sut (System Under Test) instance using the setter.

We then create the request and response instances and set the requested page.

Finally we find the handler adapter bean as defined in the Spring application configuration. The assertThat (which is from AssertJ library) checks if the handler bean is configured to handle the controller under test. If not, there is no meaning to continue the tests (first piece of our integration test).

The first test is to check what happens when the logged user is an administrator:

@Test
public void userIsAdministrator() {
  // given
  doReturn(createAdministrator()).when(userManager).getCurrentUser();
  // when
  final ModelAndView mav = handlerAdapter.handle(request, response, sut);
  // then
  assertModelAndView(mav, LandingPageController.ADMIN_MAIN);
}

In the given section, we defined the return value for the mocked UserManager.getCurrentUser method, with the help of a private method (“createAdministrator()), see below.

In the when section, we invoke the handler which is the same method invoked by Spring when a real HTTP request reaches our application. This is the real integration test.

Finally, in the then section, we check the results, using a utility method (see below).

Similar tests (not shown) for the other types of user.

At the end we have the utility methods, to check the ModelAndView instance and to create a dummy user.

private static void assertModelAndView(final ModelAndView pMav, final String pLandingPage) {
  assertThat(pMav.getView()).isNotNull().isInstanceOf(RedirectView.class);
  final RedirectView view = (RedirectView) pMav.getView();
  assertThat(view.getUrl()).isEqualTo(pLandingPage);
}

private static User createAdministrator() {
  final User ris = new User();
  ris.setRole(“ADM”);
  return ris;
}
}

Conclusion: Mockito is very useful even if without runner and annotations.