作为Mockito Junit的初学者,这听起来可能是个很丢人的问题,但我还是想确认一下:
Class1 input1;
@Mock
Class2 input2;
private Class3 obj;
@Before
public void setup() {
this obj = new Class3(input1, input2);
}
@Test
public void doTest() {
val result1 = obj.method1(input1); // return sth.
val result2 = obj.method2(input2); // return null.
}
因此将input1和input2传递到Class3 obj中,但是只有input2是模拟依赖项。然后,当我调用依赖于input2的method2时,发现它只是返回null。
那么任何嘲笑的类本质上都是null?这就是为什么我们需要在when ... thenReturn用于模拟类时使用?毕竟,我们的目的是测试主要功能,而不是依赖项。
我的理解正确吗?
答案 0 :(得分:1)
是的,您的理解是正确的。
如果您使用了适当的运行器(junit4)或扩展名(junit5),则模拟对象也不为null(即使其toString
方法可能返回类似于"null"
的东西)。
但是,可能的问题是您的Class3#method2
使用的Class2
模拟方法返回了空值。
实际上,这种行为是需要的。在这里,您可以选择:
使用注释@Mock (answer = Answers.RETURNS_DEEP_STUBS)
使您的模拟返回深层存根,这种方式是Class2
的任何方法(既不是最终方法,也不返回原始类型或包装类型)将返回一个模拟,并且该模拟的任何方法将返回一个模拟,依此类推。
明确声明模拟应如何表现,例如:Mockito.when(input2.myMethod()).thenReturn("test");
。由Mockito提供的subbing API的文档非常详尽:https://static.javadoc.io/org.mockito/mockito-core/2.23.0/org/mockito/Mockito.html#stubbing
希望这会有所帮助,
答案 1 :(得分:1)
模拟类不为null。它是具有与原始类相同签名的骨骼,但是没有实现。它可以“查看”对所有方法的调用,因此可以在以后进行验证。因此,模拟是一个不起作用的对象。它不能存储数据,也不能执行方法。您只能控制对其的所有调用以及该模拟的所有返回值。如果您需要一些更高级的模拟,则应使用@Spy
。间谍是一个“模拟”,但具有原始实现:它是一种检测到的类,可检测对它的所有调用并控制输出,但BUT也具有原始存储功能和实际调用。
进行实际通话的另一种方法是通过这种构造:
Mockito.when(myMockedObject).thenCallRealMethod();
在单元测试中,最佳实践是仅测试要测试的一个类,而不使用基础类。听起来像是一扇敞开的门,但实际上并非如此。您要测试的类所使用的所有类都应该被模拟。使用该模拟,您可以完全控制返回值,并且可以测试该类的所有极端情况。所有被模拟的类都应通过自己的单元测试进行测试。这就带来了下一个问题:测试使用的所有类都应该是可注入的或可更改的。您希望能够注入一个模拟,而不是真正的数据库驱动程序,以便查看是否进行了所有正确的调用。