EasyMock: Void Methods
I have a method that returns void in a class that is a dependency of the class I want to test.
This class is huge and I'm only using this single method from it. I need to replace the implementation of this method for the test as I want it to do something different and I need to be able to access the parameters this method receives.
I cannot find a way of doing this in EasyMock. I think I know how to do it with Mockito by using doAnswer
but I don't want to add another library unless absolutely necessary.
If I understand what you want to do correctly, you should be able to use andAnswer()
:
mockObject.someMethod(eq(param1), eq(param2));
expectLastCall().andAnswer(new IAnswer() {
public Object answer() {
//supply your mock implementation here...
SomeClass arg1 = (SomeClass) getCurrentArguments()[0];
AnotherClass arg2 = (AnotherClass) getCurrentArguments()[1];
arg1.doSomething(blah);
//return the value to be returned by the method (null for void)
return null;
}
});
The EasyMock User Guide explains:
Creating Return Values or Exceptions
Sometimes we would like our mock object to return a value or throw an exception that is created at the time of the actual call. Since EasyMock 2.2, the object returned by
expectLastCall()
andexpect(T value)
provides the methodandAnswer(IAnswer answer)
which allows [you] to specify an implementation of the interfaceIAnswer
that is used to create the return value or exception.Inside an
IAnswer
callback, the arguments passed to the mock call are available viaEasyMock.getCurrentArguments()
. If you use these, refactorings like reordering parameters may break your tests. You have been warned.
If you just call the void method for each time you're expecting it to be invoked and then invoke EasyMock.expectLastCall()
prior to calling replay()
, Easymock will “remember” each invocation.
So I don’t think you need to explicitly call expect()
(other than lastCall
) since you’re not expecting anything from a void method, except its invocation.
Thanks Chris!
“Fun With EasyMock” by fellow StackOverflow user Burt Beckwith is a good blog post that provides more detail. Notable excerpt:
Basically the flow that I tend to use is:
- Create a mock
- call
expect(mock.[method call]).andReturn([result])
for each expected call- call
mock.[method call]
, thenEasyMock.expectLastCall()
for each expected void call- call
replay(mock)
to switch from “record” mode to “playback” mode- inject the mock as needed
- call the test method
- call
verify(mock)
to assure that all expected calls happened
If you only want access to the parameters for later, you might also appreciate the Captures class which is new to EasyMock 2.4.
You can use an instance of the "Capture" class in place of a matcher. When your mocked method is invoked, the Capture instance will store the parameter it was invoked with.
Capture<ChartPanel> captured = new Capture<ChartPanel>();
// setChartPanel is going to be called during execution;
// we want to verify some things about the ChartPanel
// instance it's invoked with
chartMock.setChartPanel(capture(captured));
replay(chartMock);
ufdm.setChartAnnotater(chartMock);
// afterPropertiesSet triggers the setChartPanel call...
ufdm.afterPropertiesSet();
verify(chartMock);
// verify some things about the ChartPanel parameter our
// mock object was invoked with
assertSame(plot, captured.getValue().getChart().getPlot());
You might want to check out PowerMock. EasyMock is based on the proxy reflection API meaning everything is a proxy and you can only test interfaces, and thus only non-final methods and classes. This might work for some, but if you're testing the world as built, you'll need more power.
With PowerMock the Java 5 instrumentation API removes the limitations. No need to write mock object implementations of the object to be tested (just ugly IMO). Couple PowerMock with Mockito (or JMockit) and you'll really be off to the races.
Of course, there is the other direction of rewriting your code to be more easily tested, which is generally a good idea too, if possible.