【问题标题】:Mock dependency class is essentially null?模拟依赖类本质上是空的?
【发布时间】:2018-10-20 00:43:10
【问题描述】:

作为 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 是 Mocked 依赖。然后我发现当我调用依赖于input2的method2时,它只是返回null。

那么任何模拟类本质上都是空的?这就是为什么我们需要使用 when...thenReturn 来模拟类?毕竟,我们的目的是测试主要功能,而不是依赖关系。

我的理解正确吗?

【问题讨论】:

    标签: junit dependency-injection mockito


    【解决方案1】:

    模拟类不为空。它是一个与原始类具有相同签名的骨架,但没有实现。它可以“查看”对所有方法的调用,因此可以在之后进行验证。因此,模拟是一个不起作用的对象。它不能存储数据,也不能执行方法。您只能控制对它的所有调用以及模拟的所有返回值。如果你需要一些更高级的模拟,你应该使用@Spy。间谍是一个“模拟”,但具有原始实现:它是一个检测类来检测对它的所有调用并控制输出,但也具有原始存储设施和真实调用。

    另一种进行实际调用的方法是通过以下构造: Mockito.when(myMockedObject).thenCallRealMethod();

    在单元测试中,最好只测试你正在测试的一个类,而不测试底层类。这听起来像是一扇敞开的门,但实际上并非如此。您正在测试的类使用的所有类都应该被模拟。使用模拟,您可以完全控制返回值,并且可以测试该类的所有极端情况。所有被模拟的类都应该通过它们自己的单元测试进行测试。这带来了下一个问题:所有使用的类都应该可以通过测试注入或更改。您希望能够注入模拟而不是真正的数据库驱动程序,以便查看是否进行了所有正确的调用。

    【讨论】:

      【解决方案2】:

      是的,你的理解是正确的。

      如果您使用了适当的运行器 (junit4) 或扩展 (junit5),则您的模拟对象不为空(即使其 toString 方法可能返回类似于 "null" 的内容)。

      但是,可能存在的问题是您的 Class3#method2 使用了 Class2 的模拟方法,该方法返回 null。

      事实上,这种行为是需要的。在这里您可以选择:

      • 使用注解@Mock (answer = Answers.RETURNS_DEEP_STUBS) 让你的模拟返回deep stubs,这样Class2 的任何方法(不是最终的,也不是返回原始类型或包装类型)都将返回一个mock,并且这个 mock 的任何方法都会返回一个 mock 等等。

      • 明确声明模拟应该如何表现: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

      希望这会有所帮助,

      【讨论】:

        猜你喜欢
        • 2015-12-21
        • 1970-01-01
        • 1970-01-01
        • 2019-02-27
        • 2021-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多