延迟EasyMock验证

时间:2010-01-05 09:03:46

标签: java unit-testing junit mocking easymock

我正在使用EasyMock为Java中的JUnit测试创建模拟对象。我创建了一个模拟对象并将其传递给另一个需要调用方法的线程。在另一个线程中,调用包含在try/catch(Throwable)块中,因此当模拟上发生意外调用并因此抛出AssertionError时,catch块会捕获该错误并进行处理。因此,即使发生了意外的呼叫,测试也会通过。

为了让测试按预期失败,我想延迟对最后在测试运行程序线程中进行的EasyMock.verify(mock)调用的所有调用验证。这可能吗?如何?

4 个答案:

答案 0 :(得分:1)

我猜的正确解决方法是停止捕捉Throwable。这样做会抓住你发现的所有Error,这可能非常危险......你绝对肯定100%确定你需要抓住Throwable吗?为什么呢?

(如果事实证明你做了,你可以专门抓住AssertionError然后重新抛出它。但这太丑了!)

答案 1 :(得分:1)

我不确定如何使用EasyMock执行此操作,但Mockito可以实现此行为,因为验证断言可以在测试结束时指定。

答案 2 :(得分:0)

尝试使用漂亮的模拟:

http://easymock.org/EasyMock2_5_2_Documentation.html

“漂亮的模拟 在createMock()返回的Mock对象上,所有方法的默认行为是为所有意外的方法调用抛出AssertionError。如果你想要一个“漂亮的”Mock对象,默认情况下允许所有方法调用并返回适当的空值(0,null或false),请改用createNiceMock()。 “

对于意外调用将返回默认值而不是抛出AssertionError,但您仍然可以使用verify()方法验证它们(在这种情况下将抛出AssertionErrors)

答案 3 :(得分:0)

正如@deterb建议的那样,Mockito可以使用,但您必须知道方法名称,或者必须为每种方法设置期望值。这是一个例子:

模拟界面:

public interface MyInterface {

    void allowedMethod();

    void disallowedMethod();
}

捕获AssertionError的用户类:

public class UserClass {

    public UserClass() {
    }

    public static void throwableCatcher(final MyInterface myInterface) {
        try {
            myInterface.allowedMethod();
            myInterface.disallowedMethod();
        } catch (final Throwable t) {
            System.out.println("Catched throwable: " + t.getMessage());
        }
    }
}

Mockito测试:

@Test
public void testMockito() throws Exception {
    final MyInterface myInterface = mock(MyInterface.class);

    UserClass.throwableCatcher(myInterface);

    verify(myInterface, never()).disallowedMethod(); // fails here
}

EasyMock也是如此,但需要做一些工作:

@Test
public void testEasyMock() throws Exception {
    final AtomicBoolean called = new AtomicBoolean();
    final MyInterface myInterface = createMock(MyInterface.class);
    myInterface.allowedMethod();

    myInterface.disallowedMethod();
    final IAnswer<? extends Object> answer = new IAnswer<Object>() {

        @Override
        public Object answer() throws Throwable {
            System.out.println("answer");
            called.set(true);
            throw new AssertionError("should not call");
        }

    };
    expectLastCall().andAnswer(answer).anyTimes();

    replay(myInterface);

    UserClass.throwableCatcher(myInterface);

    verify(myInterface);
    assertFalse("called", called.get()); // fails here
}

不幸的是,您还必须知道此处的方法名称,您必须定义myInterface.disallowedMethod()expectLastCall().andAnswer(answer).anyTimes()等期望。

另一种可能性是使用Proxy class(使用自定义InvocationHandler)创建代理并将其用作模拟对象。它肯定需要更多的工作,但它可能是最可定制的解决方案。

最后不要忘记,也可以使用或不使用EasyMock模拟对象创建自定义实现。这是一个代表团:

public class MockedMyInterface implements MyInterface {

    private final MyInterface delegate;

    private final AtomicBoolean called = new AtomicBoolean();

    public MockedMyInterface(final MyInterface delegate) {
        this.delegate = delegate;
    }

    @Override
    public void allowedMethod() {
        delegate.allowedMethod();
    }

    @Override
    public void disallowedMethod() {
        called.set(true);
        throw new AssertionError("should not call");
    }

    public boolean isCalled() {
        return called.get();
    }

}

对它的测试:

@Test
public void testEasyMockWithCustomClass() throws Exception {
    final MyInterface myInterface = createMock(MyInterface.class);
    myInterface.allowedMethod();

    final MockedMyInterface mockedMyInterface = 
        new MockedMyInterface(myInterface);

    replay(myInterface);

    UserClass.throwableCatcher(mockedMyInterface);

    verify(myInterface);
    assertFalse("called", mockedMyInterface.isCalled()); // fails here
}