我有计数方法调用与Mockito的问题。问题是我想要计数的方法在测试类中被其他方法间接调用。下面是代码:
public class ClassForTest {
private Integer value;
public void doSmth() {
prepareValue("First call");
prepareValue("Second call");
prepareValue("Third call");
System.out.println(value);
}
protected void prepareValue(String msg) {
System.out.println("This is message: " + msg);
value++;
}
}
和测试类:
public class ClassForTestTest extends TestCase {
@Test
public void testDoSmth() {
ClassForTest testMock = mock(ClassForTest.class);
doNothing().when(testMock).prepareValue(anyString());
testMock.doSmth();
verify(testMock, times(3)).prepareValue(anyString());
}
}
有这样的例外:
Wanted but not invoked:
classForTest.prepareValue(<any>);
-> at org.testing.ClassForTestTest.testDoSmth(ClassForTestTest.java:24)
However, there were other interactions with this mock:
-> at org.testing.ClassForTestTest.testDoSmth(ClassForTestTest.java:21)
有什么想法吗?提前感谢!
可以。使用spy
调用底层方法。确保value
先初始化。
@Test
public void testDoSmth() {
ClassForTest testMock = spy(new ClassForTest());
testMock.doSmth();
verify(testMock, times(3)).prepareValue(anyString());
}
public class ClassForTest {
private Integer value = 0;
public void doSmth() {
prepareValue("First call");
prepareValue("Second call");
prepareValue("Third call");
System.out.println(value);
}
protected void prepareValue(String msg) {
System.out.println("This is message: " + msg);
value++;
}
}
这表明您需要进行一些重构来改进您的设计。单个类应该是完全可测试的,而不需要模拟出它的一部分。您认为需要模拟的任何部分都应该提取到一个或多个协作对象中。不要落入部分模拟的陷阱。听听测试告诉你什么。未来的自己会感谢你的。
您正在模拟被测试的类。mock用于测试类的依赖关系,而不是类本身。
我怀疑你要的是Mockito.spy()
。但是,这是Mockito Javadoc建议反对的部分mock 。
或者,如果您想为可测试性而重构,您可以这样做:
@Test
public void testDoSmth() {
Preparer preparer = mock(Preparer.class);
ClassForTest cft = new ClassForTest(preparer);
cft.doSmth();
verify(preparer, times(3)).prepareValue(anyString());
}
public class ClassForTest {
private final Preparer preparer;
public ClassForTest(Preparer preparer) {
this.preparer = preparer;
}
public void doSmth() {
preparer.prepareValue("First call");
preparer.prepareValue("Second call");
preparer.prepareValue("Third call");
System.out.println(preparer.getValue());
}
}
public class Preparer {
private Integer value = 0;
public void prepareValue(String msg) {
System.out.println("This is message: " + msg);
value++;
}
public Integer getValue() {
return value;
}
}