我正在使用EasyMock为Java中的JUnit测试创建模拟对象。我创建了一个模拟对象并将其传递给另一个需要调用方法的线程。在另一个线程中,调用包含在try/catch(Throwable)
块中,因此当模拟上发生意外调用并因此抛出AssertionError
时,catch块会捕获该错误并进行处理。因此,即使发生了意外的呼叫,测试也会通过。
为了让测试按预期失败,我想延迟对最后在测试运行程序线程中进行的EasyMock.verify(mock)
调用的所有调用验证。这可能吗?如何?
答案 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
}