#50 Mock continues after error

open
nobody
EasyMock (40)
5
2013-11-29
2011-10-18
Micha Riser
No

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

Discussion

  • Micha Riser

    Micha Riser - 2011-10-18
     
  • Micha Riser

    Micha Riser - 2011-10-18

    patch to fix tests

     
  • Micha Riser

    Micha Riser - 2011-10-18

    example test from the description

     

Log in to post a comment.