Posts Tagged ‘mocking’

Mocking Statics and java.lang.IllegalStateException: no last call on a mock available

If you use PowerMock to mock a static object e.g.

mockStatic(FacesContext.class)

and encounter the following error:

java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:174)
at org.easymock.EasyMock.expect(EasyMock.java:156)

Check that you have prepared the Class for test using the @PrepareForTest annotation.

e.g.

@RunWith(PowerMockRunner.class)
@PrepareForTest(
{
	FacesContext.class
})
public class ....

An excellent article discussing mocking statics by one of the PowerMock developers can be found here: http://blog.jayway.com/2009/05/17/mocking-static-methods-in-java-system-classes/

Note that you also need to @PrepareForTest any classes where you are expecting a private method call with expectPrivate.  If you don’t, your test execution will try and go into the private method and actually run all the code. The @PrepareForTest annotation can either go at the method level as shown in the example below, or at the class level as shown in the example posted above.

@PrepareForTest(ClassUnderTest.class)
@Test
public void testNext() throws Exception
{
	String privateMethod = "isNextEnabled";
	ClassUnderTest partMock = createPartialMock(ClassUnderTest.class, privateMethod);
	expectPrivate(partMock, privateMethod).andReturn(true);
	replayAll();
	partMock.next();
	verifyAll();
}

Chaining EasyMock’s expectation return values

Recently I discovered quite a handy feature of EasyMock’s IExpectationSetters andReturn method. You are able to chain the return values so that you can return different values each time that expectation is called.

It becomes useful if you consider the following method, where Voucher is an object that cannot be instantiated and needs to be mocked:

public class VoucherHelper
{
	public static boolean isVoucherExpired(Voucher voucher)
	{
		boolean expiredVoucher = true;
		Date expiryDate = voucher.getExpiryDate();
		if (expiryDate != null)
		{
			Date now = new Date();
			expiredVoucher = now.after(expiryDate);
		}
		return expiredVoucher;
	}
}

To test this method, there are 3 tests that need to be done.

  • expiryDate returning null
  • expiryDate returning an earlier date than the current date
  • expiryDate returning a later date than the current date

This can all be done in one expectation line by chaining the ‘andReturn’ of the expectation.

@Test
public final void testIsVoucherExpired()
{
	Voucher voucher = createMock(Voucher.class);
	Calendar expiredDate = Calendar.getInstance();
	// Make it expired by taking a year off
	expiredDate.set(Calendar.YEAR, expiredDate.get(Calendar.YEAR) - 1);

	Calendar notExpired = Calendar.getInstance();
	// Make it not expired by adding a year
	notExpired.set(Calendar.YEAR, notExpired.get(Calendar.YEAR) + 1);

	// Test with date returning null, then returning expired, then returning not expired
	expect(voucher.getExpiryDate())
		.andReturn(null)
		.andReturn(expiredDate.getTime())
		.andReturn(notExpired.getTime());
	replayAll();
	assertTrue(VoucherHelper.isVoucherExpired(voucher));
	assertTrue(VoucherHelper.isVoucherExpired(voucher));
	assertFalse(VoucherHelper.isVoucherExpired(voucher));
	verifyAll();
}

EasyMock also allows chaining on the times method and the andThrow method, and all can be used at the same time if you wanted.

expect(voucher.getExpiryDate())
	.andReturn(null).times(2)
	.andThrow(new RuntimeException())
	.andReturn(new Date()).times(3);