为什么模拟测试框架有用?

时间:2016-11-14 16:30:16

标签: testing mocking tdd mockito

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

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

public int add(int a, int b) {return a+b}

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

通过我在Mockito看到的所有例子,人们正在做when.Object.add(2,3).thenReturn(5)之类的事情。使用这个测试框架有什么意义,如果您所做的只是告诉对象如何在测试方面而不是对象方面采取行动?

2 个答案:

答案 0 :(得分:4)

模拟框架适用于通过模拟系统的依赖关系来测试系统;如果您正在测试add,则不会使用模拟框架来模拟或存根add。让我们进一步解决这个问题:

测试add

模拟框架 不适合测试上面的add方法。除了非常稳定且经过良好测试的JVM和JRE之外,没有依赖关系。

public int add(int a, int b) {return a+b}

但是,如果要与另一个对象进行交互,那么测试你的add方法可能会有好处:

public int add(int a, int b, AdditionLogger additionLogger) {
    int total = a + b;
    additionLogger.log(a, b, total);
    return total;
}

如果还没有编写AdditionLogger,或者编写它是为了与真实服务器或其他外部进程通信,那么模拟框架绝对有用:它可以帮助你想出一个虚假的AdditionLogger实现,这样你就可以了测试你的真实方法与它的互动。

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

测试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;
}

有了这个,你可能很难对这个方法编写一个健壮的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));
}

总结

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

答案 1 :(得分:0)

单元测试的目标是在不连接任何外部系统的情况下测试功能。如果要连接到任何外部系统,则认为是集成测试。

在执行单元测试时,系统可能需要一些可以在系统/集成测试期间从外部系统检索的数据,如数据库,Web /休息服务,API等。在这种情况下,我们需要提供模拟/虚假数据来测试一些业务规则或任何其他形式的逻辑。

如上所述,单元测试确保特定的代码单元与给定的假/模拟数据集一起工作,并且在集成环境中应该以类似的方式运行。