首页 > 解决方案 > Mockito ArgumentCaptor 不会在 catch 块中捕获参数

问题描述

我写了这个服务

public class FirstService {

    private final SecondService secondService;

    public FirstService(SecondService secondService) {
        this.secondService = secondService;
    }

    public void hz() throws Exception {
        try {
            methodThrowsException();
        } catch (Exception e){
            secondService.handleErrorMessage(e.getMessage());
            throw e;
        }
    }

    private void methodThrowsException() throws Exception {
        throw new Exception("message");
    }
}

而这项服务:

public class SecondService {
    public void handleErrorMessage(String message) {}
}

我需要验证它是否handleErrorMessage被调用。我写了一个测试:

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class FirstServiceTest {
    private FirstService firstService;
    private SecondService secondService;

    @Before
    public void setUp() {
        secondService = mock(SecondService.class);
        firstService = new FirstService(secondService);
    }

    @Test(expected = Exception.class)
    public void hz() throws Exception {
        firstService.hz();
        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(secondService).handleErrorMessage(argumentCaptor.capture());
        String value = argumentCaptor.getValue();

        assertEquals("message", value);
    }
}

测试通过。但如果我改变assertEquals("message666", value);它仍然通过。如果我没有在 catch 块中抛出异常 - ArgumentCaptor 会捕获参数,但是当我抛出异常时它不起作用。

标签: javajunitmockito

解决方案


您的测试已注释: @Test(expected = Exception.class)

这意味着如果一个Exception(或其任何子类)达到最高级别,则测试将通过。这发生在测试的第一行:

    firstService.hz();

这就是它通过的原因。不幸的是,该异常意味着您的测试的其余部分永远不会运行,因为该异常会向上传播并从您的测试方法中传播出去。

有点难看,但是这个片段可以满足您的要求:

    @Test
    public void hz() throws Exception {

        try {
            firstService.hz();

            // If we get here, then we didn't throw an exception - fail
            Assert.fail();
        } catch (Exception ex) {
            // Exception was expected - disregard and continue
            // no-op
        }
        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(secondService).handleErrorMessage(argumentCaptor.capture());
        String value = argumentCaptor.getValue();

        assertEquals("message", value);
    }

以上运行您的方法,并捕获异常(如果您没有得到预期的异常则失败)。然后,它继续,并运行你的测试的其余部分。

JUnit 5 提供了一种更简洁的方式,但您必须迁移:

    @Test
    public void hz() throws Exception {

        Assertions.assertThrows(Exception.class, () -> firstService.hz());

        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
        verify(secondService).handleErrorMessage(argumentCaptor.capture());
        String value = argumentCaptor.getValue();

        assertEquals("asdf", value);
    }

推荐阅读