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

Why are mocking test frameworks helpful?

似乎我看过的所有 Mockito 示例,"fake" 他们正在测试的对象的行为。

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

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

我会简单地使用 JUnit 断言传入的两个整数是否会产生正确的输出。

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

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

测试add

模拟框架适合测试上面的add方法。除了非常稳定且经过严格测试的 JVM 和 JRE 之外,没有其他依赖项。

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

但是,如果它像这样与另一个对象交互:

,那么测试您的添加方法可能会有好处
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 等知名接口进行交互时,可以更轻松地解释模拟和模拟语法,但这些示例通常不是模拟的真实情况是需要的。请记住,当您不能使用真实的 .

时,模拟仅对 模拟被测系统周围的依赖关系真正有用。

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

在执行单元测试时,系统可能需要一些数据,这些数据可能在 Systems/Integration 测试期间从外部系统检索为数据库、web/rest 服务、API 等。在这种情况下,我们需要提供 mock/fake 数据来测试某些业务规则或任何其他形式的逻辑。

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