Mockito ArgumentCaptor捕获了大量重复记录

时间:2017-06-09 21:24:45

标签: java multithreading junit mockito

我试图使用Mockito和JUnit来测试多线程应用程序。以下是一些有问题的代码:

ArgumentCaptor<MessageCreator> messageCaptor = ArgumentCaptor.forClass(MessageCreator.class);

jmsHandler.put(message);

Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture());

jmsHandler.put(message)行将String放入应用程序,该应用程序进入BlockingQueue并从多线程部分开始。然后我等待该方法在接下来的10秒内执行4次并捕获结果。

应用程序应该吐出MessageCreator的4个实例,出于我的目的,这只是一个包含String的对象,然后我将与预期的输出进行比较。测试期间的日志记录确认正在创建4条消息。

当我尝试循环使用ArgumentCaptor的{​​{1}}方法检查结果时,我注意到getAllValues()正在复制我的程序&#39; s输出数百万次。它应该有4个对象,但最后一次运行有6,984,988。

这个数字似乎在某种程度上是可变的,但是当我在调试模式中使用测试时序时,它会发生巨大变化。例如,如果我在List行设置断点,然后跳过该断点,并等待应用程序在开始jmsHandler步骤之前完成处理,则Mockito.verify(...)大小会直线下降到&#34;仅仅&#34; 158,636件物品。

之前是否有其他人遇到此类问题?如果我能提供更多详细信息,请通知我。

编辑:这是测试和程序结构的独立示例:

List

这是运行该测试的输出:

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class MultiThreadTest {
    private Input inputHandler;
    @Mock
    private JmsTemplate mockJmsTemplate;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);

        inputHandler = new Input();
        inputHandler.setQueue(queue);

        Output outputHandler = new Output();
        outputHandler.setQueue(queue);
        outputHandler.setJmsTemplate(mockJmsTemplate);
        new Thread(outputHandler).start();
    }

    @Test
    public void testMessage() {
        ArgumentCaptor<OutputMessageCreator> messageCaptor = ArgumentCaptor.forClass(OutputMessageCreator.class);

        String inMessage = "testMessage";

        List<String> expectedMessages = new ArrayList<String>(4);

        inputHandler.put(inMessage);

        Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture());
        System.out.println("Number: " + messageCaptor.getAllValues().size());
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(0)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(1)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(2)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(3)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(4)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(5)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(6)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(7)));
        System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(8)));

        List<String> outMsgs = new ArrayList<String>();
        for (OutputMessageCreator creator : messageCaptor.getAllValues()) {
            outMsgs.add(creator.getMsg());
        }
        assertEquals(expectedMessages, outMsgs);
    }

    private class Input {
        private BlockingQueue<String> queue;

        public void put(String msg) {
            try {
                queue.put(msg);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void setQueue(BlockingQueue<String> queue) {
            this.queue = queue;
        }
    }

    private class Output implements Runnable {
        private BlockingQueue<String> queue;
        private JmsTemplate jmsTemplate;
        private int counter = 1;

        @Override
        public void run() {
            while (true) {
                String msg = null;
                try {
                    msg = queue.take();
                    String[] messagesOut = new String[4];
                    for (int i = 0; i < 4; i++) {
                        messagesOut[i] = msg + "-" + counter++;
                    }

                    for (String messageOut : messagesOut) {
                        System.out.println(messageOut);
                        jmsTemplate.send(new OutputMessageCreator(messageOut));
                        Thread.sleep(2000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void setQueue(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        public void setJmsTemplate(JmsTemplate jmsTemplate) {
            this.jmsTemplate = jmsTemplate;
        }
    }

    private class OutputMessageCreator implements MessageCreator {
        private String msg;

        public OutputMessageCreator(String msg) {
            this.msg = msg;
        }

        @Override
        public Message createMessage(Session session) throws JMSException {
            TextMessage message = session.createTextMessage();
            message.setText(msg);
            return message;
        }

        public String getMsg() {
            return msg;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

在某些时候,这似乎是Mockito中的一个错误:

https://github.com/mockito/mockito/issues/345

https://github.com/mockito/mockito/issues/379

问题似乎暗示这已在Mockito 2或2.1中得到修复,但我使用2.0.41-beta并尝试了2.4.0和2.8.9并得到了相同的结果。在github问题的一些评论中,似乎有各种各样的解决方法。

这行代码:

Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture());

可以替换为:

try {
    Thread.sleep(10000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

Mockito.verify(mockJmsTemplate, Mockito.times(4)).send(messageCaptor.capture());

我已就问题379发表评论,看看该修复程序是否已实际发布,但似乎这项工作现在可以解决问题。