Introduction:
EasyMock works by implementing the proxy pattern. When you create a mock object, it creates a proxy object that takes the place of the real object. The proxy object gets it's definition from the interface you pass when creating the mock. We will define what methods are called and their returns from within our test method itself.
When creating a mock object, there are two types, a mock and a strict mock. In either case, our test will tell the mock object what method calls to expect and what to return when they occur. A basic mock will not care about the order of the execution of the methods. A strict mock, on the other hand, is order specific. Your test will fail if the methods are executed out of order on a strict mock.
In this example, we will be using a strict mock.
private LoginServiceImpl service;
private UserDAO mockDao;
@Override
public void setUp() {
service = new LoginServiceImpl();
mockDao = createStrictMock(UserDAO.class);
service.setUserDAO(mockDao);
}
User results = new User();
String userName = "testUserName";
String password = "testPassword";
String passwordHash = "someunecryptedpass";
expect(mockDao.loadByUsernameAndPassword(eq(userName), eq(passwordHash))).andReturn(results);
replay(mockDao);
assertTrue(service.login(userName, password));
verify(mockDao);
expect(<<method name>>)
This is a call to the static method EasyMock.expect. It tells your mock object to expect the method loadByUsernameAndPassword to be called.
eq(userName), eq(passwordHash)
When EasyMock compares the values passed to the method call, it does and == comparison. The eq comparator in this case will compare the contents of the string using it's .equals method.
.andReturn(results);
This tells our mock object what to return after this method is called.
We can as well use expectAndReturn() single method call instead of calling expect() and andReturn() method seperatly.
The final three lines are the ones that do the testing work. replay(mockDao); tells EasyMock "We're done declaring our expectations. It's now time to run what we told you".
Finally, verify(mockDao); tells EasyMock to validate that all of the expected method calls were executed and in the correct order.
Example 1:
Let's say we have a PageCachingFilter which will add few response headers to remove caching.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse sResponse = (HttpServletResponse)response;
sResponse.addHeader("Cache-Control","no-cache");
sResponse.addHeader("Pragma","no-cache");
chain.doFilter(request, response);
}
Our TestCase will look something like below
public void testCacheHeaders()
{
// Create mock controllers
MockControl requestControl = MockControl.createControl(HttpServletRequest.class);
MockControl responseControl = MockControl.createControl(HttpServletResponse.class);
MockControl filterChainControl = MockControl.createControl(FilterChain.class);
// Create the mock objects
HttpServletRequest request = (HttpServletRequest)requestControl.getMock();
HttpServletResponse response = (HttpServletResponse)responseControl.getMock();
FilterChain filterChain = (FilterChain)filterChainControl.getMock();
// Record the expectation
response.addHeader("Cache-Control","no-cache");
response.addHeader("Pragma","no-cache");
try
{
filterChain.doFilter(request, response);
}
catch(Exception e)
{
fail(e.getMessage());
}
// Stop recording
requestControl.replay();
responseControl.replay();
filterChainControl.replay();
// Execute the test
Filter filter = new PageCachingFilter();
try
{
filter.init(null);
filter.doFilter(request, response, filterChain);
filter.destroy();
}
catch(Exception e)
{
fail(e.getMessage());
}
// Verify the expectations against the test
requestControl.verify();
responseControl.verify();
filterChainControl.verify();
}
IMPORTANT NOTE 1: Please note that spring helps a bit further and eases mock object creation of HttpServletRequest,Response and FilterChain objects.
Hence ideally in a single step we can create the mock object unlike the 2 steps described above.
import org.easymock.MockControl;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
public void setUp()
{
filter = new UserFilter();
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
session = new MockHttpSession();
chain = new MockFilterChain();
Principal principal = new Principal() {
public String getName()
{
return "TheName";
}};
request.setUserPrincipal(principal);
}
IMPORTANT NOTE 2: We can also set the return value of a mock object using setReturnValue() method.
Example:
User user = new User();
user.setName("TheName");
MockControl userServiceControl = MockControl.createControl(IUserService.class);
userServiceControl.setReturnValue(user);
IMPORTANT NOTE 3:
Below code will show us how to create a Mock ServletContext which can accept the file names which we normally mention in web.xml as a parameter to get loaded.
servletContext = new MockServletContext();
String configFiles = "/WEB-INF/config/framework/config.xml ";
servletContext.addInitParameter("CONFIG_FILE", configFiles);
Below code will show us how to create a StaticWebApplicationContext and attach it to the created ServletContext.
Servlet Context is known can be created from the above code.
StaticWebApplicationContext applicationContext = new StaticWebApplicationContext();
applicationContext.setServletContext(servletContext);
applicationContext.refresh();
applicationContext.start();
servletContext.setAttribute(XmlWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
IMPORTANT NOTE 4:
If we want to test spring 3.0 front-end controllers below is sample code
import org.junit.Test;
import org.springframework.web.servlet.ModelAndView;
import static org.junit.Assert.assertNotNull;
public class TestHomeController extends BaseTestController {
private HomeController controller;
private final static String URI = "/home.html";
@Test
public void testHomeController() throws Exception {
request.setRequestURI(URI);
this.controller = new HomeController();
ModelAndView view = controller.home(request,response);
assertNotNull(view);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
"classpath:spring/demo-servlet.xml"})
@TransactionConfiguration(transactionManager = "transactionManager")
public class BaseTestController {
protected MockHttpServletRequest request;
protected MockHttpServletResponse response;
protected MockHttpSession session;
@Before
public void setUp() throws Exception {
System.out.println("Doing set-up");
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
}
@After
public void tearDown() throws Exception {
System.out.println("Doing tearDown");
}
}
demo-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">property name="maxUploadSize" value="10000000"/>
</bean>
....
</beans>
References
httstrong>
<!-- Maximum file size in bytes. -->
<property name="maxUploadSize" value="10000000"/>
</bean>
....
</beans>
References
http://www.michaelminella.com/testing/unit-testing-with-junit-and-easymock.html
http://www.easymock.org/Downloads.html
http://easymock.org/api/easymock/2.4/index.html?org/easymock/MockControl.html
Monday, 8 August 2011
Working With JUnit And Mock Objects
Subscribe to:
Post Comments (Atom)
1 comment:
Thanks for the post!
Post a Comment