似乎我看过的所有 Mockito 示例都“伪造”了他们正在测试的对象的行为。
如果我有一个具有方法的对象:
public int add(int a, int b) {return a+b}
我会简单地使用 JUnit 断言传入的两个整数是否会产生正确的输出。
在我见过的所有 Mockito 示例中,人们都在做类似 when.Object.add(2,3).thenReturn(5)
的事情。如果您所做的只是告诉对象如何在测试端而不是对象端采取行动,那么使用这个测试框架有什么意义?
最佳答案
模拟框架非常适合通过模拟系统的依赖项来测试系统;如果您正在测试 add
,则不会使用模拟框架来模拟或 stub 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
的调用没有什么特别危险的,所以假设它存在,您可能可以在外部测试中调用真实的。 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
等知名接口(interface)进行交互时,可以更轻松地解释模拟和模拟语法,但这些示例通常不是需要模拟的现实案例。请记住,模拟仅在您不能使用真实依赖项时才真正有用模拟被测系统周围的依赖项。
关于testing - 为什么模拟测试框架有帮助?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40593477/