我将以以下背景作为开场白:我是一个新手,在测试方面没有太多经验,而且以前从未使用过mocking框架。
我正在为代码编写单元测试,这些代码命中了许多不同的web服务,我曾嘲笑过这些代码。我的许多测试都会验证调用的结果,其中除了对ServiceX的调用之外,所有的服务调用都是成功的。我的第一个直觉是为@Before块中的所有mock设置快乐路径行为,然后修改每个测试的mock行为。
@Before
public void init(){
when(serviceA.doSomething()).thenReturn(true);
when(serviceB.doSomething()).thenReturn(true);
when(serviceC.doSomething()).thenReturn(true);
when(serviceD.doSomething()).thenReturn(true);
when(serviceE.doSomething()).thenReturn(true);
}
@Test
public void testDoBusinessSuccess(){
String result = businessLogic.doBusiness();
assertThat(result, is("success"));
}
@Test
public void testDoBusinessFailureWhenServiceAFails(){
when(serviceA.doSomething()).thenReturn(false);
String result = businessLogic.doBusiness();
assertThat(result, is("service A is down!"));
}
@Test
public void testDoBusinessFailureWhenServiceBFails(){
when(serviceB.doSomething()).thenReturn(false);
...这使得每个测试用例都很简洁,而且很容易看到正在测试的是什么,因为我只指定了偏离规范的行为。
但我怀疑这不是莫基托希望我设置模拟行为的方式,因为当我试图验证ServiceB中的失败意味着serviceC永远不会命中时,我意识到我在@Before中对when(serviceC.doSomething())的调用被算作ServiceC上的调用。也就是说,我的verifyZeroInteractions(serviceC)总是失败,因为我调用了when(serviceC.doSomething()).thenReturn(true),即使测试用例在其他方面从未触及过serviceC。
那么最佳实践是什么呢?在每次测试中显式地为每个mock设置行为是不是更好,即使我会在所有地方重复几乎相同的5行?
发布于 2012-10-25 12:42:21
when(serviceC.doSomething()) in the @Before counted as invocations on serviceC我怀疑when构造是否被视为调用,因为这只是存根。
您是否可以仔细检查代码以查看是否从@Test内部调用了serviceC.doSomething
关于最佳实践,我认为您应该只将所有测试用例都常见的存根行为转移到@Before中
除了代码的外观之外,我认为您可以尝试将其重构为Chain of Responsibility模式,应该可以帮助您编写测试代码。
发布于 2012-10-25 12:39:15
这并不是专门针对mocking的,但是只有对每个测试都通用的代码才应该放在@ test中,因为它是在每个junit测试之前执行的。
因此,如果您想要特定于测试的行为,那么所有的模拟内容都应该包含在这些测试中。
如果您有多个测试共有的行为,您可以将其提取到一个方法中,该方法仅由那些需要该行为的测试调用。
发布于 2012-10-26 00:36:34
verify正在计数的调用是测试方法本身中的调用。将each方法中的调用更改为如下所示。
doReturn(false).when(serviceA).doSomething();就存根而言,这与您正在做的事情具有相同的效果;但是为了验证的目的,它不会被算作调用doSomething。
https://stackoverflow.com/questions/13061581
复制相似问题