3

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

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

4

4 回答 4

1

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

(如果事实证明你这样做了,你可以AssertionError专门捕捉并重新抛出它。但这很难看!)

于 2010-01-05T09:15:27.713 回答
1

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

于 2010-01-05T13:13:43.747 回答
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另一种可能性是使用类(使用 custom )创建代理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
}
于 2012-06-29T20:01:34.550 回答
0

尝试使用漂亮的模拟:

http://easymock.org/EasyMock2_5_2_Documentation.html

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

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

于 2010-01-05T14:37:46.050 回答