Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences

Edit this page


Referenced by
Articles




JSPWiki v2.2.33

[RSS]


Hide Menu

AppFuseEasyMock


Simplify you test using EasyMock

This articel will give a short overview how to integrate EasyMock in AppFuse.

For further questions you can contact me at josip(at)esistegalaber(dot)de

I assume that you have a running AppFuse project:

  • [1] Download a suitable version of EasyMock
  • [2] Integrate the libraries in AppFuse
  • [3] Write some Tests using EasyMock
  • [4] Run the Tests and have fun.
  • [5] Change all AppFuse (1.9) Service tests to easymock (optional)
  • [6] Take a moment to think of what is happening...

Download a suitable version of EasyMock [#1]

  • The latest version of Easymock is 2.0 but this version works only with Java 2 Version 5.0 and above. As I use Java 1.4x the rest of this tutorial is based on EasyMock 1.2.

Integrate the libraries in AppFuse [#2]

  • Create a new folder named 'easymock-1.2' int the /lib directory of your AppFuse project.
  • Copy easymock.jar in the new directory
  • Add the following part to the lib/lib.properties file:

#
# EasyMock - http://www.easymock.com
#
easymock.version=1.2
easymock.dir=${lib.dir}/easymock-${easymock.version}
easymock.jar=${easymock.dir}/easymock.jar
  • Finally you have to add the reference to the easymock.jar to the service test classpath (or whatever module you want to mock). In order to do this, you have to edit your properties.xml file and add the following element to your service.test.classpath:

So the complete service.test.classpath would look like

    <path id="service.test.classpath">
        <path refid="service.compile.classpath"/>
        <pathelement location="${junit.jar}"/>
        <pathelement location="${log4j.jar}"/>
        <pathelement location="${log4j.jar}"/>
    	<fileset dir="${servletapi.dir}" includes="*.jar"/>
        <pathelement location="${jakarta-oro.jar}"/>
        <pathelement location="${dumbster.jar}"/>
        <pathelement location="${jmock.jar}"/>
        <pathelement location="${easymock.jar}"/>
        <path location="test/dao"/>
    </path>
  • If you are using Eclipse, you also have to add the easymock.jar to your buildpath (Project properties -> java buildpath -> jar)

Now you are set up to write some tests with EasyMock.

Write the tests. [#3]

Basically I will rewrite the PeronManagerTest known from the Appfuse tutorial. Using EasyMock the Testcase will be set up like this:


package org.appfuse.service;

import org.appfuse.dao.PersonDao;

import org.appfuse.model.Person;

import org.appfuse.service.impl.PersonManagerImpl;

import org.easymock.MockControl;
import org.springframework.orm.ObjectRetrievalFailureException;


public class PersonManagerTest extends BaseManagerTestCase
{
  //create a PersonManager instance to be tested.
  private PersonManager personManager = new PersonManagerImpl();
  //create a MockControl-object to retrieve and control a mock.
  private MockControl   personDaoControl = MockControl.createStrictControl(PersonDao.class);
  //create an mocked instance of the PersonDao the manager depends on.
  private PersonDao     personDao = (PersonDaopersonDAOControl.getMock();

  /**
   @see junit.framework.TestCase#setUp()
   */
  protected void setUp() throws Exception
  {
    super.setUp();
    //inject the mocked DAO into the Manager
    personManager.setPersonDao(personDao);
  }

  /**
   @see junit.framework.TestCase#tearDown()
   */
  protected void tearDown() throws Exception
  {
    super.tearDown();
    //clean up.
    personDao          = null;
    personDaoControl   = null;
    personManager      = null;
  }
}

The difference to Mocktests known from the tutorial is simply that we don't use the Mock themselves but an MockControl that will ease the use of the actual Mock. In this case I use the static Method MockControl.createStrictControl(PersonDao.class); that will create a MockControl object that will take care of ordering of methodcalls to the Mocked object. Let's take a look at the actual TestMethods:


  /*
   * Test method for 'com.bomber.service.impl.PersonManagerImpl.getPerson(String)'
   */
  public void testGetPerson()
  {
    //create testdata
    Person person = new Person();
    person.setId(new Long(1));
    person.setFirstName("Matt");
    person.setLastName("Raible");

    //set expectations
    personDao.getPerson(new Long(1));
    personDaoControl.setReturnValue(person);

    //call to the method to be tested
    personDaoControl.replay()//set the mockcontrol to replay-state

    Person testPerson = personManager.getPerson("1")//actual methodcall
    assertEquals("Wrong person retrieved!", person, testPerson)//test the returned data
    personDaoControl.verify()//verify the mockobject
  }

  /*
   * Test method for 'com.bomber.service.impl.PersonManagerImpl.removePerson(String)'
   */
  public void testRemovePerson()
  {
    //set expectations
    personDao.removePerson(new Long(1));
    personDaoControl.replay()//set the mockcontrol to replay-state
    personManager.removePerson("1");
    personDaoControl.verify()//verify the mockobject
  }

  /*
   * Test method for 'com.bomber.service.impl.PersonManagerImpl.savePerson(Person)'
   */
  public void testSavePerson()
  {
    //create testdata
    Person person = new Person();
    person.setId(new Long(1));
    person.setFirstName("Matt");
    person.setLastName("Raible");

    //set expectations
    personDao.savePerson(person);

    //test the methodcall
    personDaoControl.replay()//set the mockcontrol to replay-state
    personManager.savePerson(person);
    personDaoControl.verify()//verify the mockobject
  }
  /*
   * Test method for 'com.bomber.service.impl.PersonManagerImpl.getPerson(Person)'
   */
  public void testGetPersonThatDoesntExist()
  {
    //set expectations
    personDao.getPerson(new Long(1));
    //tell the mock to throw an exception
    personDaoControl.setThrowable(new ObjectRetrievalFailureException(Person.class, new Long(1)));
    //set the MockControl to replay-state
    personDaoControl.replay();
    
    try
    {
      personManager.getPerson("1");
      fail("Excpected Exception not thrown!");
    }
    catch (Exception e)
    {
      assertNotNull(e);
      personDaoControl.verify();
    }
  }

I think this form of mocking your test is very simple to understand. The MockControl simply keeps track of the calls you make to the mocked instance. This way it becomes very easy to write down your expectations and the rather complicated setup of expectations using bare Mocks is not needed anymore. Just like with bare Mocks you can set (void) return values or exceptions to be thrown. There are even convenience methods to specify that a method i supposed to be called n times. For more information on what EasyMock can do for you visit the EasyMock Documentation.

Run the tests [#4]

All that is left to do is run the test. Either execute ant test-service or call the single testcase by executing ant test-service -Dtestcase=PersonManager. Hopefully I haven't misstyped anything and you will see a BUILD SUCCESSFULL Yeah Baby, Yeah! Have fun!

Change all AppFuse (1.9) Service tests to easymock [#5]

Download the RAR file and extract all tests to your test/service folder. Maybe you have to change the package names...

Some further thougts. [#6]

I consider Mocks to be a bit more than just a means of White Box Tests. As the term itself indicates you need to have some knowlegde of the tested code in order to write a meaningful test. In contrast to Black box Tests where you don't care about the code itself, but only about the outcome of the test it will give you some information about the code you wrote. So, as a rule of thumb I belive that if you have difficulties writing a mock test for you business object that simply means your business object is designed badly. Therefore my paradigm concerning mock tests is simply:
"If you can't test it - refactor it!".
Comments appreciated!


Go to top   Edit this page   More info...   Attach file...
This page last changed on 06-Nov-2006 13:53:00 MST by JosipMihelko.