You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JUnit测试报错:无法实例化@InjectMocks字段问题求助

问题描述

编写JUnit 4测试时遇到org.mockito.exceptions.misusing.InjectMocksException错误,提示无法实例化@InjectMocks标注的mQMessageChecker字段,构造或初始化块抛出IllegalArgumentException。

测试类代码:

@SpringBootTest
@RunWith( MockitoJUnitRunner.class )
public class MQMessageCheckerTest {
    
    @Mock
    JmsTemplate jmsTemplate;
    
    @Mock
    RestServiceConnector restServiceConnector;

    @Mock
    TextMessage textMessage;

    @InjectMocks
    MQMessageChecker mQMessageChecker;
    
    @Mock
    ExecutorService executorService;
    
    @Test
    public void testCheckMQForMessages() {
        mQMessageChecker.checkMQForMessages();
    }
}

MQMessageChecker类代码:

public class MQMessageChecker {

@Value("${scbnhub.qname}")
private String queueName;

@Value("${mq.threadPoolMax}")
private int threadPool;

@Autowired
private JmsTemplate jmsTemplate;

@Autowired
RestServiceConnector restServiceConnector;

protected static final String TIMESTAMP = "timestamp";
private final ExecutorService executorService = Executors.newFixedThreadPool(threadPool);


/**
 * scheduler added to make the call frequently
 */
@Scheduled(fixedRate = 1000)
public void checkMQForMessages() {
    String selector = TIMESTAMP + " <= " + System.currentTimeMillis();
    receiveAndPrintMessages(queueName, selector);
}
}

错误信息:

[ERROR] testShutdownExecutorService(com.ibm.wce.scbn.api2api.api2apijobs.service.MQMessageCheckerTest) Time elapsed: 8.455 s  <<< ERROR!
    org.mockito.exceptions.misusing.InjectMocksException:
    
    Cannot instantiate @InjectMocks field named 'mQMessageChecker' of type 'class com.ibm.wce.scbn.api2api.api2apijobs.service.MQMessageChecker'.
    You haven't provided the instance at field declaration so I tried to construct the instance.
    However the constructor or the initialization block threw an exception : null
    
    Caused by: java.lang.IllegalArgumentException
问题原因与解决方法

问题根源

错误核心原因:

  • MQMessageChecker中的threadPool字段通过@Value注入配置值,但测试用的MockitoJUnitRunner不会处理Spring的@Value注解,导致threadPool默认值为0。
  • 初始化executorService时调用Executors.newFixedThreadPool(threadPool),线程池大小不能为0,直接抛出IllegalArgumentException,进而导致Mockito无法实例化目标类。

解决方法

方法1:改用Spring测试运行器

将测试类的运行器改为SpringRunner,让Spring容器处理@Value和依赖注入,配合@SpringBootTest加载上下文:

@SpringBootTest
@RunWith(SpringRunner.class)
public class MQMessageCheckerTest {
    
    @Autowired
    MQMessageChecker mQMessageChecker;
    
    @MockBean
    JmsTemplate jmsTemplate;
    
    @MockBean
    RestServiceConnector restServiceConnector;
    
    @Test
    public void testCheckMQForMessages() {
        mQMessageChecker.checkMQForMessages();
    }
}

同时在src/test/resources下创建测试用的application.properties:

scbnhub.qname=test-queue
mq.threadPoolMax=5

方法2:添加构造函数注入

给MQMessageChecker添加全参数构造函数,将依赖和配置值都作为参数传入,测试时手动控制参数值:

public class MQMessageChecker {

    private String queueName;
    private int threadPool;
    private JmsTemplate jmsTemplate;
    private RestServiceConnector restServiceConnector;
    private final ExecutorService executorService;

    public MQMessageChecker(@Value("${scbnhub.qname}") String queueName,
                           @Value("${mq.threadPoolMax}") int threadPool,
                           @Autowired JmsTemplate jmsTemplate,
                           @Autowired RestServiceConnector restServiceConnector) {
        this.queueName = queueName;
        this.threadPool = threadPool;
        this.jmsTemplate = jmsTemplate;
        this.restServiceConnector = restServiceConnector;
        this.executorService = Executors.newFixedThreadPool(threadPool);
    }

    // 原有方法...
}

测试时直接实例化目标类,传入mock对象和合法的线程池大小:

@RunWith(MockitoJUnitRunner.class)
public class MQMessageCheckerTest {
    
    @Mock
    JmsTemplate jmsTemplate;
    
    @Mock
    RestServiceConnector restServiceConnector;

    MQMessageChecker mQMessageChecker;
    
    @Before
    public void setUp() {
        mQMessageChecker = new MQMessageChecker("test-queue", 5, jmsTemplate, restServiceConnector);
    }
    
    @Test
    public void testCheckMQForMessages() {
        mQMessageChecker.checkMQForMessages();
    }
}

方法3:用反射工具设置字段值

在测试的@Before方法中,使用Spring的ReflectionTestUtils手动设置threadPool等字段的值,避免初始化出错:

@RunWith(MockitoJUnitRunner.class)
public class MQMessageCheckerTest {
    
    @Mock
    JmsTemplate jmsTemplate;
    
    @Mock
    RestServiceConnector restServiceConnector;

    MQMessageChecker mQMessageChecker;
    
    @Before
    public void setUp() {
        mQMessageChecker = new MQMessageChecker();
        ReflectionTestUtils.setField(mQMessageChecker, "threadPool", 5);
        ReflectionTestUtils.setField(mQMessageChecker, "queueName", "test-queue");
        ReflectionTestUtils.setField(mQMessageChecker, "jmsTemplate", jmsTemplate);
        ReflectionTestUtils.setField(mQMessageChecker, "restServiceConnector", restServiceConnector);
        ReflectionTestUtils.setField(mQMessageChecker, "executorService", Executors.newFixedThreadPool(5));
    }
    
    @Test
    public void testCheckMQForMessages() {
        mQMessageChecker.checkMQForMessages();
    }
}

内容的提问来源于stack exchange,提问作者vijay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:32:51