为什么模拟测试框架会有所帮助?

Jos*_*ith 1 testing tdd mocking mockito

似乎我看过的所有Mockito示例都“伪造”了他们正在测试的对象的行为。

如果我有一个具有方法的对象:

public int add(int a, int b) {return a+b}
Run Code Online (Sandbox Code Playgroud)

我只是使用JUnit断言传入的两个整数是否会导致正确的输出。

通过我在Mockito中看到的所有示例,人们正在做类似的事情when.Object.add(2,3).thenReturn(5)。如果您正在做的只是告诉对象如何在测试端而不是对象端起作用,那么使用此测试框架有什么意义?

Jef*_*ica 5

模拟框架非常适合通过模拟系统的依赖关系来测试系统。add如果您正在测试,则不会使用模拟框架进行模拟或存根add。让我们进一步介绍一下:

测试中 add

模拟框架不利于测试add上述方法。除了非常稳定且经过充分测试的JVM和JRE,没有其他依赖项。

public int add(int a, int b) {return a+b}
Run Code Online (Sandbox Code Playgroud)

但是,如果它要与另一个对象进行交互,则可能适合测试您的add方法:

public int add(int a, int b, AdditionLogger additionLogger) {
    int total = a + b;
    additionLogger.log(a, b, total);
    return total;
}
Run Code Online (Sandbox Code Playgroud)

如果尚未编写AdditionLogger,或者编写它是为了与真实服务器或其他外部进程进行通信,那么模拟框架绝对有用:它将帮助您提出伪造的AdditionLogger实现,以便您测试真实的方法的相互作用。

@Test public void yourTest() {
    assertEquals(5, yourObject.add(2, 3, mockAdditionLogger));
    verify(mockAdditionLogger).log(2, 3, 5);
}
Run Code Online (Sandbox Code Playgroud)

测试add的消费者

巧合的是,模拟框架也不太适合测试上述方法的使用者。毕竟,对的调用没有什么特别危险的add,因此假设存在,您可以在外部测试中调用真实的调用。2 + 3将始终等于5,并且您的计算没有任何副作用,因此通过模拟或验证几乎无济于事。

但是,让我们为您的对象提供另一个方法,该方法将两个数字相加并带有一点随机噪声:

public int addWithNoise(int a, int b) {
    int offset = new Random().nextInt(11) - 5;  // range: [-5, 5]
    int total = a + b + offset;
    return total;
}
Run Code Online (Sandbox Code Playgroud)

这样,您可能很难assert针对此方法编写健壮的样式测试。毕竟,结果将是随机的!相反,为了使assert样式测试更容易,也许我们可以进行存根分析addWithNoise以使其中的一些更可预测。

@Test public void yourTest() {
    when(yourObjectMock.addWithNoise(2, 3)).thenReturn(6);
    // You're not asserting/verifying the action you stub, you're making the dependency
    // *fast and reliable* so you can check the logic of *the real method you're testing*.
    assertEquals(600, systemUnderTestThatConsumesYourObject.doThing(yourObjectMock));
}
Run Code Online (Sandbox Code Playgroud)

综上所述

与类似的知名操作add或类似的接口进行交互时,更容易解释模拟和模拟语法List,但是这些示例通常不是需要模拟的现实情况。请记住,当您不能使用真实的模拟时,模拟仅对模拟被测系统周围的依赖性非常有用。