在Mockito中重用模拟行为/最佳实践?

时间:2012-10-25 04:32:32

标签: java unit-testing mockito

我将以背景为前提,我非常环保,并且在测试方面没有多少经验,之前从未使用过模拟框架。

我正在编写针对许多不同Web服务的代码的单元测试,我已经嘲笑过了。我的许多测试验证了呼叫的结果,其中除了调用ServiceX之外,我的所有服务调用都成功。我的第一直觉是为@Before块中的所有模拟设置happy-path行为,然后修改每个测试的模拟行为。

@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);

...

这使得每个测试用例简洁,并且很容易看到正在测试的内容,因为我只指定了偏离规范的行为。

但我怀疑这不是Mockito希望我设置模拟行为的方式,因为当我试图验证ServiceB中的故障意味着ServiceC从未被命中时,我意识到我在when(serviceC.doSomething())中的调用@Before计为serviceC上的调用。也就是说,我的verifyZeroInteractions(serviceC)总是失败,因为我已经调用了when(serviceC.doSomething()).thenReturn(true),即使测试用例从未触及过serviceC。

那么最佳做法是什么?我最好只是为每个测试中的每个模拟显式设置行为,即使我在整个地方重复几乎相同的5行?

3 个答案:

答案 0 :(得分:2)

when(serviceC.doSomething()) in the @Before counted as invocations on serviceC

我怀疑when构造被视为一个调用,因为那只是存根  您是否可以仔细检查代码,看看是否在serviceC.doSomething

中调用@Test

关于最佳实践,我认为您应该只将所有测试用例中常见的存根行为转移到@Before

除了代码查看方式之外,我认为您可以尝试重构为Chain of Responsibility模式, this 可以帮助您编写测试代码。

答案 1 :(得分:0)

这不是特定于模拟,但只有每个测试通用的代码都应该放在@Before中,因为它在每次junit测试之前执行。

因此,如果您想要特定于测试的行为,那么所有模拟内容都应该在那些测试中。

如果您有多于1个测试的共同行为,则可以将其提取到仅由那些需要该行为的测试调用的方法中。

答案 2 :(得分:0)

verify正在计数的调用是测试方法本身的调用。将每个方法中的调用更改为如下所示。

doReturn(false).when(serviceA).doSomething();

这与你所做的事情具有相同的效果;但出于验证目的,它不会被视为doSomething的调用。