Mockito在将argThat与自定义ArgumentMatcher一起使用时获取NPE

dkqlctbz  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(325)

我尝试使用自定义的ArgumentMatcher,但总是得到NPE,对我来说,现在很难找到原因,即使我在文档中找到了相关的NPE。

@Test
    void debug() {

        class ListGetMatcher implements ArgumentMatcher<Integer> {
            public boolean matches(Integer index) {
                return index == 2;
            }

        }

        List mock = mock(List.class);

        when(mock.get(argThat(new ListGetMatcher()))).thenReturn(200);

        assertEquals(200, mock.get(2));

        //when(mock.addAll(argThat(new ListOfTwoElements()))).thenReturn(true);

        //mock.addAll(Arrays.asList("one", "two"));

        //verify(mock).addAll(argThat(new ListOfTwoElements()));

    }

我只是改为使用intThat,它工作得很好。

doReturn(200).when(mock).get(intThat(new ListGetMatcher()));

但以下情况仍会引起NPE。

when(substationQueryExecutor.getSubById(argThat(argument -> argument.getId() == 1L))).thenReturn(new Substation());

当参数的id为999时,我希望返回Substation。我该怎么办?
下面是更详细的代码,我是getSubById()的stub,它有一个SubstationQueryCmd参数类型,我希望根据SubstationQueryCmd的id值返回不同的值。当我调试代码时,我发现matches()的回调总是传递给我一个null而不是SubstationQueryCmd对象。我不明白问题出在哪里,也许你知道。

@Slf4j
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class SubPowerSaveExecutorTest {

    @InjectMocks
    private SubPowerSaveExecutor executor;

    @Mock
    private SubstationQueryExecutor queryExecutor;

    @BeforeEach
    public void setup() {
        MockitoAnnotations.openMocks(this);
    }

    static class SubstationQueryArgMatcher implements ArgumentMatcher<SubstationQueryCmd> {

        private final Long id;

        public SubstationQueryArgMatcher(Long id) {
            this.id = id;
        }

        @Override
        public boolean matches(SubstationQueryCmd argument) {
            // I debugged the code and found that the argument is null every time, I think this is the problem
            return argument.getId().longValue() == id;
        }
    }

    @Test
    void test() {

        when(queryExecutor.getSubById(argThat(new SubstationQueryArgMatcher(1L)))).thenReturn(new Substation());
        when(queryExecutor.getSubById(argThat(new SubstationQueryArgMatcher(999L)))).thenReturn(null);

        List<SubPowerDto> datas = new ArrayList<>();
        datas.add(new SubPowerDto().setMeterNum("meter01").setProviderName("diehl").setDate("2022-04-24 10:10:00").setSubstationId(1L).setPower(1D));
        datas.add(new SubPowerDto().setMeterNum("meter01").setProviderName("diehl").setDate("2022-04-24 10:20:00").setSubstationId(1L).setPower(1D));
        datas.add(new SubPowerDto().setMeterNum("meter01").setProviderName("diehl").setDate("2022-04-24 10:30:00").setSubstationId(1L).setPower(1D));

        datas.add(new SubPowerDto().setMeterNum("meter01").setProviderName("diehl").setDate("2022-04-24 10:30:00").setSubstationId(999L).setPower(1D));
        // getSubById() will be called in filterData
        List<SubPower> subPowers = executor.filterData(datas);
        assertEquals(1, subPowers.size());

    }

}
s4n0splo

s4n0splo1#

因为您使用argThat.作为源代码:

public static <T> T argThat(Matcher<T> matcher) {
        return reportMatcher(matcher).<T>returnNull();
    }

要解决此问题,只需更改为使用intThat

public static int intThat(Matcher<Integer> matcher) {
        return reportMatcher(matcher).returnZero();
    }

你的第二个问题:您可能会误解ArgumentMatcher的用法。
您的方法queryExecutor.getSubById的参数为Long,但您使用:

ArgumentMatcher<SubstationQueryCmd>

这是不正确的。请将其更改为:

ArgumentMatcher<Long>

然后,您可以使用longThat而不是argThat
substationQueryExecutor.getSubById的情况下,参数为SubstationQueryCmd
然后,您只需要在自定义匹配器中选中null

@Override
        public boolean matches(SubstationQueryCmd argument) {
            if (argument == null) {
                return false;
            }
            return argument.getId().longValue() == id;
        }

因为:这是一个对象,它可能是null。所以,这发生在你试图存根的那一行。所以,如果你使用下面的语法,你需要在你的自定义参数匹配器中检查null

when(...).thenReturn(...)

若要避免变更自订参数比对器,您可以改为使用下列语法:

doReturn(...).when(yourMock).doSomething()

因此,您的代码应该是:

doReturn(new Substation()).when(queryExecutor).getSubById(argThat(new SubstationQueryArgMatcher(1L)));
        doReturn(null).when(queryExecutor).getSubById(argThat(new SubstationQueryArgMatcher(999L)));

快乐编码!

相关问题