public enum Position { BOSS, PROGRAMMER, SURFER } public interface ICalcMethod { double calc(Position position); } 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); } }
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(); } }
软件不是以孤立的方式完成工作,而是大部分单元相互协作完成的。但在单元测试中我们希望忽略协作单元的使用细节,以达到独立完成测试工作的目的。Mock对象能帮助我们在测试环境下代替协作伙伴。而EasyMock为类和接口使用Mock对象提供了一种简单的方式。
对一个类(而非接口)生成mock对象,需要额外jar包Objenesis和Cglib(见附件);
如果是一个相对复杂的测试用例,需要对多个接口生成mock对象,使用MockControl来管理。
关于easymock更详尽的描述和使用技巧,请参考:
http://www.ibm.com/developerworks/cn/java/j-easymock.html