When a call on the mock does not match the expectation, an AssertionError is thrown. So far, so good. But if further calls are made to the mock - either by catching all Throwables or by some finally block the mock continues and the previous error gets forgotten. This makes it hard to find out where the first error occured or makes tests succeed where it should be red.
Consider the following example:
public class FinallyTest {
public interface I {
public void foo(String s);
}
public static class A {
public void run1(I i) { try { i.foo("hello"); // error is here } finally { i.foo("done"); // reported is here } } public void run2(I i) { try { i.foo("hello"); i.foo("world"); } catch(Throwable t) { } }
}
@Test
public void test1() {
IMocksControl control = EasyMock.createStrictControl();
I mock = control.createMock(I.class);
// expectation mock.foo("foo"); mock.foo("done"); control.replay(); new A().run1(mock); control.verify();
}
@Test
public void test2() {
IMocksControl control = EasyMock.createStrictControl(); I mock = control.createMock(I.class); // expectation mock.foo("hello"); control.replay(); new A().run2(mock); control.verify();
}
}
Running test1, the reported error is
java.lang.AssertionError:
Unexpected method call foo("done"):
foo("foo"): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:45)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:73)
at $Proxy4.foo(Unknown Source)
at FinallyTest$A.run1(FinallyTest.java:21)
at FinallyTest.test1(FinallyTest.java:47)
This is wrong. The reported error is from the finally block not from where the first error has occurred - by calling foo("hello") instead of the expected foo("foo").
Running test2, there is no error at all. This is wrong. The call foo("world") has been too much. This needs to be reported in the mock verification!
To fix this problems, the control must remember the first error that occurs and re-throw it when further invocations are made or when verify is called. There is no point in trying to match further expectations after the first expectation mismatch!
The attached "source.patch" changes the MocksBehavior to remember the first error and re-throw it.
The unit tests for easymock rely on the fact that AssertionError can be catched, ignored and the mock used further. This conflicts the changes. Therefore, the second patch "tests.patch" adds the ability to explicitly clear the error state of the mock and adds the neccessary calls to the tests.
The attached
patch to fix tests
example test from the description