Mockito的@After和verifyNoMoreInteractions

时间:2018-11-09 22:15:49

标签: java junit mockito

我想确保每个测试都验证其模拟的所有交互,所以我只是添加了一个用@After注释的方法,并带有一个verifyNoMoreInteractions并将所有模拟作为参数。

@After
public void after(){
  verifyNoMoreInteractions(mock1,mock2,mock3,...)
}

它可以工作,但是如果在没有预期的交互作用下发生交互,您怎么知道哪个测试是有问题的呢?

3 个答案:

答案 0 :(得分:2)

@After在此类的每次测试完成执行后立即执行。不管测试是否失败。然后,如果在@After方法中发生错误,则可以掩盖/隐藏在测试方法中发生的错误...

请注意,@AfterClass是在此类的所有测试完成执行之后执行的。

总的来说,我发现将行为测试分为三个部分是很好的样式-称为A / A / A或称为Given / When / Then

安排/给定的部分: 设置对象和行为

行为或时间: 执行实施

确认或然后: 验证行为和结果(提示:verifyNoMoreInteractions的去向)

答案 1 :(得分:2)

您正在滥用方法verifyNoMoreInteractions()。您应该在每个要验证的测试中调用它。

另一方面,@After应该用于清理/关闭测试方法所使用的资源。

您需要的是自定义TestWatcher规则。参见以下此类规则的示例:

public class VerifyNoMoreInteractionsRule extends TestWatcher {

    private final List<Object> mocks = new ArrayList<>();

    public void add(Object mock){
        mocks.add(mock);
    }

    @Override
    protected void succeeded(Description description) {
        verifyNoMoreInteractions(mocks.toArray());
    }

}

然后您可以在单元测试中使用它:

@RunWith(MockitoJUnitRunner.class)
public class VerifyTest {

    @Rule
    public VerifyNoMoreInteractionsRule noMoreInteractionsRule = new VerifyNoMoreInteractionsRule();

    @Mock
    private YourMock yourMock;

    @Mock
    private AnotherMock anotherMock;

    @Before
    public void setUp(){
        // Register the mocks you want to verify after each test
        noMoreInteractionsRule.add(yourMock);
        noMoreInteractionsRule.add(anotherMock);
    }

    @Test
    public void test(){
        // Put your ordinary test code here
    }

}

该规则将应用于每个测试。

答案 2 :(得分:0)

对于 JUnit5,可以使用 AfterEachMethodAdapter 来检查测试是否抛出异常。如果是,则没有验证任何模拟:

public class MockAwareTest {

    @RegisterExtension
    public MockVerifier mockVerifier = new MockVerifier();


    @BeforeEach
    void setUp() {
        mockVerifier.addMocks(...);
    }

}

还有MockVerifier

public class MockVerifier implements AfterEachMethodAdapter {

    private final List<Object> mocks = new LinkedList<>();

    public void addMocks(final Object... mock) {
        mocks.addAll(asList(mock));
    }

    @Override
    public void invokeAfterEachMethod(
            final ExtensionContext context,
            final ExtensionRegistry registry) {
        // if the test didn't fail, check the mocks
        if (context.getExecutionException().isEmpty()) {
            verifyNoMoreInteractions(mocks.toArray());
        }
    }

}