我有一个非常简单的方法,我正在尝试进行单元测试:
public class MyAntTask extends org.apache.tools.ant.Task {
public void execute() {
fire();
}
public void fire() {
// Do stuff
}
}
我只想写一个单元测试来确认调用execute()
总是调用fire()
,所以我写了这个:
@Test
public void executeCallsFire() {
//GIVEN
MyAntTask myTask = Mockito.mock(MyAntTask.class);
// Configure the mock to throw an exception if the fire() method
// is called.
Mockito.doThrow(new RuntimeException("fired")).when(myTask).fire();
// WHEN
try {
// Execute the execute() method.
myTask.execute();
// We should never get here; HOWEVER this is the fail() that's
// being executed by JUnit and causing the test to fail.
Assert.fail();
}
catch(Exception exc) {
// THEN
// The fire() method should have been called.
if(!exc.getMessage().equals("fired"))
Assert.fail();
}
}
我想(我绝不是专家)Mockito通常不能模拟返回void
的方法,但这是一种变通方法。你基本上说"用一个Mock
包装我的对象,每当一个特定的方法即将被执行时,它总是会返回一个特定RuntimeException
"。因此,Mockito并没有真正执行fire()
,而是看到它即将执行并抛出异常。执行已验证?检查
它没有通过,而是在对myTask.execute()
的调用正下方的第一个Assert.fail()
处失败。
就我的一生而言,我不明白为什么。以下是JUnit为我提供的关于失败的巨大堆栈跟踪的前10行左右:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.fail(Assert.java:100)
at net.myproj.ant.tasks.MyAntTaskUnitTest.executeCallsFire(MyAntTaskUnitTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
这里有什么想法吗,StackOverflow的Mockito大师?提前感谢!
因为myTask是一个mock,所以根本不会调用真正的对象。要调用真实对象,请使用间谍。
您可以使用verify测试是否调用了方法,这样就不需要异常。
public void executeCallsFire() {
MyAntTask myTask = Mockito.spy(new MyAntTask());
myTask.execute();
Mockito.verify(myTask).fire();
}
不过,想要模拟您正在测试的对象似乎是不对的。通常最好设计测试,以便验证对单独对象的调用。
我在这里看到了更多的设计问题:
- 为什么需要一个行方法,而这两个方法都是公共的
- mock用于模拟依赖关系,而不是用于测试中的类
- 如果你把火(名字不太清楚)定为私人的。你不应该测试你班的私人行为