1. Unit testing with PowerMock
Open source project:
http ://code.google.com/p/powermock/
2. PowerMock features
Mocking static methods
Mocking final methods or classes
Mocking private methods
Mock construction of new objects
Partial Mocking
Replay and verify all
Mock Policies
Test listeners
4. Add to ant project
Copy jars to the test folder:
cglib-nodep-2.2.2.jar
easymock-3.1.jar
javassist-3.16.1-GA.jar
powermock-easymock-1.4.12-full.jar
objenesis-1.2.jar
Add jars to the classpath for junit task:
<path id="test.classpath">
<path refid="plugin.classpath" />
<fileset dir="${app.server.lib.portal.dir}" includes="commons-io.jar" />
<fileset dir="${project.dir}/lib" includes="junit.jar" />
<fileset dir="${project.dir}/lib/test" includes="*.jar" />
<pathelement location="test-classes" />
</path>
5. Class under test example
public class ClassUnderTest {
private MyService myService;
public String getMaxAmountForTemplate() {
String template = TemplateUtil.getTemplate("1");
BigDecimal maxAmount = myService.getMaxAmount();
return TemplateUtil.applyTemplate(template, maxAmount);
}
}
interface MyService {
BigDecimal getMaxAmount();
}
class TemplateUtil {
public static String getTemplate(String templateId) {
return "ID";
}
public static String applyTemplate(String template, Object ... params) {
return template + params.toString();
}
}
6. Unit test implementation
import java.math.BigDecimal;
public class ClassUnderTestTest {
private ClassUnderTest classUnderTest;
@org.junit.Test
public void getMaxAmountForTemplate() {
classUnderTest = new ClassUnderTest();
org.junit.Assert.assertEquals("Should be ID100", "ID100",
classUnderTest.getMaxAmountForTemplate());
}
}
7. Unit test implementation with mocks
@PrepareForTest({TemplateUtil.class })
@RunWith(PowerMockRunner.class)
public class ClassUnderTestTest {
private ClassUnderTest classUnderTest;
@org.junit.Test
public void getMaxAmountForTemplate() throws Exception {
classUnderTest = new ClassUnderTest();
PowerMock.mockStatic(TemplateUtil.class);
EasyMock.expect(TemplateUtil.getTemplate(EasyMock.eq("1"))).andReturn("ID");
EasyMock.expect(TemplateUtil.applyTemplate(EasyMock.eq("ID"), (BigDecimal)
EasyMock.anyObject())).andReturn("IDMOCK");
MyService myService = EasyMock.createMock(MyService.class);
Field field = classUnderTest.getClass().getDeclaredField("myService");
field.setAccessible(true);
field.set(classUnderTest, myService);
EasyMock.expect(myService.getMaxAmount()).andReturn(new BigDecimal("100"));
PowerMock.replayAll();
EasyMock.replay(myService);
org.junit.Assert.assertEquals("Should be IDMOCK", "IDMOCK",
classUnderTest.getMaxAmountForTemplate());
EasyMock.verify(myService);
PowerMock.verifyAll();
}
}
8. Use capture with EasyMock
public void getMaxAmountForTemplate() throws Exception {
classUnderTest = new ClassUnderTest();
PowerMock.mockStatic(TemplateUtil.class);
EasyMock.expect(TemplateUtil.getTemplate(EasyMock.eq("1"))).andReturn("ID");
Capture<BigDecimal> capturedMaxAmount = new Capture<BigDecimal>();
EasyMock.expect(TemplateUtil.applyTemplate(EasyMock.eq("ID"),
EasyMock.capture(capturedMaxAmount))).andReturn("IDMOCK");
MyService myService = EasyMock.createMock(MyService.class);
...
EasyMock.replay(myService);
org.junit.Assert.assertEquals("Should be IDMOCK", "IDMOCK",
classUnderTest.getMaxAmountForTemplate());
org.junit.Assert.assertEquals("100",
capturedMaxAmount.getValue().toString() );
EasyMock.verify(myService);
PowerMock.verifyAll();
}
9. Code emulation in mock objects
@org.junit.Test
public void getMaxAmountForTemplate() throws Exception {
classUnderTest = new ClassUnderTest();
PowerMock.mockStatic(TemplateUtil.class);
EasyMock.expect(TemplateUtil.getTemplate(EasyMock.eq("1"))).andReturn("ID");
EasyMock.expect(TemplateUtil.applyTemplate(EasyMock.eq("ID"), (BigDecimal)
EasyMock.anyObject())).andAnswer(new IAnswer<String>() {
public String answer() throws Throwable {
return EasyMock.getCurrentArguments()[0].toString() +
EasyMock.getCurrentArguments()[1].toString();
}
});
MyService myService = EasyMock.createMock(MyService.class);
Field field = classUnderTest.getClass().getDeclaredField("myService");
field.setAccessible(true);
field.set(classUnderTest, myService);
EasyMock.expect(myService.getMaxAmount()).andReturn(new BigDecimal("100"));
PowerMock.replayAll();
EasyMock.replay(myService);
org.junit.Assert.assertEquals("Should be ID100", "ID100",
classUnderTest.getMaxAmountForTemplate());
10. Skip static initialization for classes under test
public class TemplateUtil {
static {
initDatabase();
}
public static String getTemplate(String templateId) {
return "ID";
}
public static String applyTemplate(String template, Object ... params) {
return template + params[0].toString();
}
}
@SuppressStaticInitializationFor("TemplateUtil")
@RunWith(PowerMockRunner.class)
public class ClassUnderTestTest {
private ClassUnderTest classUnderTest;
11. F.I.R.S.T. properties of unit tests
Fast
Many hundreds or thousands per second
Isolates
Failure reasons became obvious
Repeatable
Run repeatedly in any order, any time
Self-validating
No manual validation required
Timely
Written before the code