同时使用 junit 断言和 mockito 验证

Using both junit assertions and mockito verification

我将 Junit 与 Mockito 结合使用。我使用mockito的verify方法+junit assertion来做完整的验证。这是不可取的吗?我们应该使用一个还是另一个而不是两者?

两者并用没有错。

Mockito 的 verify 用于断言在给定的 mock 上调用了一个方法(使用预期的参数)。

JUnit 的assertXYZ 用于断言某些结果具有预期值。

两者都是有效的验证,如果两者相关,则两者都应该使用。

例如,考虑以下(当然是人为的)情况:

您有一个执行某些数学计算的界面:

public interface ValueProducer {
    public int getValue(int val);
}

还有一个 class 可以将它产生的任何结果加倍:

public class Doubler {
    public static int doubleThatResult (ValueProducer producer, int val) {
        return 2 * producer.getValue(val);
    }
}

测试它需要断言两件事:

  1. getValue 被正确调用
  2. 结果翻倍

所以,例如:

public class DoublerTest {

    @Test
    public void testDoubleThatResult() throws Exception {
        int value = 7; // Or any other value
        int returnMock = 13; // Or any other value

        ValueProducer producerMock = mock(ValueProducer.class);
        when(producerMock.getValue(value)).thenReturn(returnMock);

        int actual = Doubler.doubleThatResult(producerMock, value);

        verify(producerMock);
        assertEquals(26, actual);
    }
}

Mureinik 的回答是绝对正确的——断言和验证是互补的,并且可以很好地协同工作——但对一个行为同时进行这两种操作可能是多余的。

目标通常是尽可能以最灵活和与实现无关的方式表达测试。从这个意义上说,状态测试(带有断言)通常是最合适的选择:只要结果状态正确,调用哪些方法并不重要。 Mockito 验证虽然可能,但可能会引入脆弱性(代码行为正确但测试被破坏)。 Mockito 本身在 verify(T)'s Javadoc and the linked article by Mockito's creator Szczepan Faber.

中对此发出警告

这种冗余当然不是最糟糕的事情:它确实测试了系统的 属性,并且在测试与敏感的、遗留的、第三方的或经常变化的依赖项的交互时可能是值得的尝试.但是,如果交互不重要,这些额外的验证可能会以脆弱性为代价。

其他时候,确认正确的行为意味着测试副作用——例如,确保 someSystem.reset() 被调用,或者通过验证提供者未被调用来测试缓存。这些是验证的完美示例,因为与外部服务的交互是关键的可测试行为。在其中一些情况下,Mockito 验证是 唯一 做出正确断言的方法。

很多测试用例都是以上的组合,所以断言和验证可以自由搭配使用;请记住,状态测试通常就足够了,而且更可取。