首页 > 解决方案 > 在 Mockito 中模拟迭代器类时遇到问题

问题描述

我正在尝试模拟一个 SOAP Interceptor 类,其中一个类方法返回一个 Iterator 对象。但是,在仔细检查语法后,迭代器并没有被真正的迭代器替换,Mockito 继续运行没有真正迭代器的方法。

我尝试使用各种模拟方法(doReturn,when...thenReturn)模拟拦截器的返回值,但这些方法都没有奏效。我不确定我在嘲笑中的错误在哪里。

这是我在测试类中模拟当前对象的方式:

@Mock private WebServiceTemplate template;
@Mock private SoapInterceptor interceptor;
@Mock private Iterator<Attachment> iterator;

    @Test
    public void testGetDocsSoapClient() {
        @SuppressWarnings("unchecked")
        Iterator<Attachment> realIterator = new ArrayListIterator();
        ObjectFactory realFactory = new ObjectFactory();

        assertFalse(realIterator.hasNext());

        doReturn(realFactory.createAwsGetDocsRequest(createMockAwsGetDocsReq()))
            .when(factory).createAwsGetDocsRequest(any (AwsGetDocsRequest.class));
        doReturn(realFactory.createAwsGetDocsResponse(createAwsGetDocsResponse()))
            .when(template).marshalSendAndReceive(any(Object.class), any(SoapActionCallback.class));
        doReturn(realIterator)
            .when(interceptor).getSoapAttachments();

这是在真实类中调用该方法的方式。

Iterator<Attachment> soapAttachments = attachmentInterceptor.getSoapAttachments();
ImageListDVO imgList = convertToImageList(soapAttachments);

...我的测试用例在这个私有方法的最后一行失败了。

private ImageListDVO convertToImageList(Iterator<Attachment> attachments) {
        ImageListDVO imgList = new ImageListDVO();

        while(attachments.hasNext()) {

我应该正确地模拟对象,但我得到一个 NullPointerException,这表明该对象没有被模拟或正确注入。

标签: javaiteratormockito

解决方案


我认为您使用了错误的语法。如果我理解正确,您需要模拟SoapInterceptor具有方法的getSoapAttachments()

为此,您需要将代码更改为以下内容:

    @InjectMocks
    // the class under test should be put here

    @Mock
    SoapInterceptor attachmentInterceptor;

    @Test
    public void testGetDocsSoapClient() {

       // this is either a real interceptor or a mocked version of it
       Iterator<Attachment> iterator = ... ;
       when(attachmentInterceptor.getSoapAttachments()).thenReturn(iterator);
    }

当您想模拟 void 方法时,通常使用 do 方法。

您还写道您已经尝试过这个,因此您可能没有正确初始化 Mockito。


确保使用正确的 Runner / Extension / Rule 或其他任何东西(如 MockitoAnnotations.initMocks(testClass))。您可能使用的 JUnit 版本之间存在某些差异。(如果您仍然需要帮助,请提供您正在使用的 JUnit 和 Mockito Verison)。

(见https://static.javadoc.io/org.mockito/mockito-core/2.28.2/org/mockito/Mockito.html#9


未注入事物的另一种可能性可能是您的类的结构以 mockito 无法处理的方式。

从您的测试用例中,我假设您使用了字段注入,因此 @Mock 注释字段应该与private您在测试类中的字段具有相同的名称。因此,我再次不确定哪一个是您没有提供名称的。

除非您手动提供 Mocks,否则您正在使用的此类应该有一个适当的 @InjectMocks 注释。(但在这种情况下,您可能不会使用 @Mock 注释)。



编辑:
您的问题的另一种解释可能是您正在尝试测试 SoapInterceptor 本身的方法,并且您想用其他方法替换返回 Iterator 的方法。

在这种情况下,您应该研究创建 aSpy而不是,您的代码应如下所示:

    @Test
    public void testGetDocsSoapClient() {

        SoapInterceptor interceptor = new SoapInterceptor();
        SoapInterceptor spy = Mockito.spy(interceptor);

        when(spy.getSoapAttachments()).thenReturn(iterator);

        ...
    }

推荐阅读