Version 1.4
Copyright © 2011, 2012, 2013 Lars Vogel
31.01.2013
| Revision History | |||
|---|---|---|---|
| Revision 0.1 | 06.02.2010 | Lars Vogel |
created |
| Revision 0.2 - 1.4 | 06.02.2010 - 31.01.2013 | Lars Vogel |
bug fixed and enhancements |
Table of Contents
The following tutorial is based on an understanding of unit testing with the JUnit framework.
In case your are not familiar with JUnit please check the following JUnit Tutorial .
The process of Unit testing is defined as testing classes or methods in isolation.
Java classes usually depend on other classes. A mock object is a dummy implementation for an interface or a class in which you define the output of certain method calls. Mock objects allow you to unit test the class which should be tested without any dependencies.
You can create these mock objects manually (via code) or use a mock framework to simulate these classes. Mock frameworks allow you to create mock objects at runtime and define their behavior.
The classical example for a mock object is a a data provider. In production a real database is used but for testing a mock object simulates the database and ensures that the test conditions are always the same.
These mock objects can be provided to the class which is tested. Therefore the class to be tested should avoid any hard dependency on external data.
Mock frameworks also allow to test the expected interaction with the mock object, e.g. you test which methods have been called on the mock object.
Popular mock frameworks are EasyMock, jMock and Mockito. The following lists the links to these frameworks.
#jMock http://jmock.org/ # EasyMock http://easymock.org/ # Mockito http://code.google.com/p/mockito/
EasyMock is a mock framework which can be easily used in conjunction with JUnit. The following description demonstrates the usage of EasyMock.
EasyMock instantiates an object based on an interface or class.
import static org.easymock.EasyMock.createNiceMock; .... // ICalcMethod is the object which is mocked ICalcMethod calcMethod = createNiceMock(ICalcMethod.class);
The
createNiceMock()
method creates a mock which returns default values for methods which
are not overiden. A mock created with the
Mock()
method will fails in such a case.
EasyMock has several methods which are used to configure the Mock
object.
The
expect()
method tells EasyMock to simulate a method
with certain
arguments. The
andReturn()
method
defines the return value of this
method for the specified method
parameters. The
times()
method defines how often the Mock object will be
called.
The
replay()
method is called to make the Mock object
available.
// setup the mock object expect(calcMethod.calc(Position.BOSS)).andReturn(70000.0).times(2); expect(calcMethod.calc(Position.PROGRAMMER)).andReturn(50000.0); // Setup is finished need to activate the mock replay(calcMethod);
Download
EasyMock
from the EasyMock Homepage
and add the
easymock.jar
library
to your classpath.
http://easymock.org/
You also
need to download the
Objenesis
and
Cglib
libraries
and add these
jars
to your classpath.
Create a new Java Project called com.vogella.testing.easymock.first. Create the following classes.
package com.vogella.testing.easymock.first; public enum Position { BOSS, PROGRAMMER, SURFER }
package com.vogella.testing.easymock.first; public interface ICalcMethod { double calc(Position position); }
package com.vogella.testing.easymock.first; public class IncomeCalculator { private ICalcMethod calcMethod; private Position position; public void setCalcMethod(ICalcMethod calcMethod) { this.calcMethod = calcMethod; } public void setPosition(Position position) { this.position = position; } public double calc() { if (calcMethod == null) { throw new RuntimeException("CalcMethod not yet maintained"); } if (position == null) { throw new RuntimeException("Position not yet maintained"); } return calcMethod.calc(position); } }
The
IncomeCalculator
class should be
tested. The
class has the
purpose to calculate the
salary of a person based on
the provided
method and
position. Obviously
the
test depends
on the
provided methods.
Create a new
test
source folder in your project.
Create a new test for
IncomeCalculator
and place the new test class in this
folder.
package com.vogella.testing.easymock.first.test; // Use static imports to // have direct access to these methods import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.junit.Before; import org.junit.Test; import com.vogella.testing.easymock.first.ICalcMethod; import com.vogella.testing.easymock.first.IncomeCalculator; import com.vogella.testing.easymock.first.Position; public class IncomeCalculatorTest { private ICalcMethod calcMethod; private IncomeCalculator calc; @Before public void setUp() throws Exception { // NiceMocks return default values for // unimplemented methods calcMethod = createNiceMock(ICalcMethod.class); calc = new IncomeCalculator(); } @Test public void testCalc1() { // Setting up the expected value of the method call calc expect(calcMethod.calc(Position.BOSS)).andReturn(70000.0).times(2); expect(calcMethod.calc(Position.PROGRAMMER)).andReturn(50000.0); // Setup is finished need to activate the mock replay(calcMethod); calc.setCalcMethod(calcMethod); try { calc.calc(); fail("Exception did not occur"); } catch (RuntimeException e) { } calc.setPosition(Position.BOSS); assertEquals(70000.0, calc.calc(), 0); assertEquals(70000.0, calc.calc(), 0); calc.setPosition(Position.PROGRAMMER); assertEquals(50000.0, calc.calc(), 0); calc.setPosition(Position.SURFER); verify(calcMethod); } @Test(expected = RuntimeException.class) public void testNoCalc() { calc.setPosition(Position.SURFER); calc.calc(); } @Test(expected = RuntimeException.class) public void testNoPosition() { expect(calcMethod.calc(Position.BOSS)).andReturn(70000.0); replay(calcMethod); calc.setCalcMethod(calcMethod); calc.calc(); } @Test(expected = RuntimeException.class) public void testCalc2() { // Setting up the expected value of the method call calc expect(calcMethod.calc(Position.SURFER)).andThrow(new RuntimeException("Don't know this guy")).times(1); // Setup is finished need to activate the mock replay(calcMethod); calc.setPosition(Position.SURFER); calc.setCalcMethod(calcMethod); calc.calc(); } }
After execution of the test you can call the
verify
method to
check if the mock object was called as defined.
Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.