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
相关产品推荐
相关产品推荐

