gpt4 book ai didi

java - Mockito ArgumentCaptor 正在捕获大量重复记录

转载 作者:太空宇宙 更新时间:2023-11-04 11:25:05 24 4
gpt4 key购买 nike

我正在尝试使用 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 次并捕获结果。

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

当我尝试循环遍历 ArgumentCaptorgetAllValues() 方法来检查结果时,我注意到 List 确实将我程序的输出复制了数百万次。它应该有 4 个对象,但上次运行有 6,984,988 个。

这个数字似乎在某种程度上是可变的,但是当我在 Debug模式下测试测试时序时,它会发生巨大的变化。例如,如果我在 jmsHandler 行设置断点,跳过该断点,并在启动 Mockito.verify(...) 步骤之前等待应用程序完成处理,则 List 大小会骤降到“仅仅”158,636 个对象。

以前有其他人遇到过此类问题吗?如果我可以提供更多详细信息,请告诉我。

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

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;
}
}
}

这是运行该测试的输出:

testMessage-1
testMessage-2
testMessage-3
testMessage-4
Number: 5392168
Equal: true
Equal: false
Equal: false
Equal: false
Equal: true
Equal: false
Equal: false
Equal: false
Equal: true

最佳答案

看起来这是 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 发表了评论,以查看该修复程序是否确实已发布,但目前看来此解决方案可以解决问题。

关于java - Mockito ArgumentCaptor 正在捕获大量重复记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44466903/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com