SpringBoot中使用MockitoJUnitRunner编写测试时出现Mock对象未初始化及参数匹配器误用异常
看起来你的测试碰到了两个关联的问题——Mock对象未初始化导致的空指针异常(NPE),以及由此引发的参数匹配器误用错误。咱们一步步拆解解决:
一、空指针异常(NPE)的核心原因与解决
错误提示里明确说mailBuilder是null,这是因为Mockito没有成功初始化这个Mock对象,根源在于JUnit版本和Mockito运行器不兼容,还有部分依赖Mock未标记:
1. 统一JUnit版本与Mockito初始化方式
你当前混用了JUnit 5的@BeforeEach注解和JUnit 4的@RunWith(MockitoJUnitRunner.class)运行器,这两者完全不兼容:
- JUnit 4用
@RunWith(MockitoJUnitRunner.class)+@Before - JUnit 5(Jupiter)用
@ExtendWith(MockitoExtension.class)+@BeforeEach
你可以二选一调整:
方案A:切换为JUnit 5的Mockito扩展
替换类上的运行器注解,改用JUnit 5的扩展类,同时确保项目依赖包含mockito-junit-jupiter:
import org.junit.jupiter.api.BeforeEach; import org.mockito.junit.jupiter.MockitoExtension; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(MockitoExtension.class) class NotificationServiceTest { // 其他代码保持不变 }
方案B:继续使用JUnit 4
把@BeforeEach改成JUnit 4的@Before注解即可:
import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) class NotificationServiceTest { // ... @Before void setUp() { // 原setUp逻辑不变 } }
2. 补全所有缺失的@Mock注解
你代码里标记了// Missing @Mock的几个服务(menageService、parentService等),如果NotificationService中依赖了这些类,必须给它们加上@Mock注解,否则@InjectMocks无法注入,后续执行也会触发NPE:
@Mock private IMenageService menageService; @Mock private IParentService parentService; @Mock private EmailService emailService; @Mock private EmailsDocumentRepository emailsDocumentRepository;
二、参数匹配器误用异常的解决
这个异常其实是NPE的连锁反应——当你在null对象上调用方法并使用Mockito参数匹配器时,Mockito会抛出这个错误。解决上面的NPE问题后,这个异常通常会自动消失。不过要记住一个Mockito的核心规则:
在Stub或验证方法时,同一个方法的所有参数必须全用匹配器,或者全用具体值,不能混合使用。
比如:
- 正确写法:
when(mailBuilder.subject(anyString(), any())).thenReturn(mailBuilder);(两个参数都是匹配器) - 错误写法:
when(mailBuilder.subject("固定标题", any())).thenReturn(mailBuilder);(混合具体值和匹配器)
你的现有Stub代码中参数匹配器的使用是合规的,所以解决NPE后这个问题就会消失。
三、额外验证步骤
- 确认所有
@Mock的类都是Mockito可Mock的类型:- 优先是接口,非final类也可以(如果是final类需要开启Mockito的final类Mock支持)
- 类类型需要有无参构造方法,或者Mockito能通过其他方式实例化
- 检查
NotificationService的注入方式:
确保它的依赖(如mailBuilder、systemeRepository等)是通过构造方法、setter或字段注入的,这样@InjectMocks才能正确把Mock对象注入进去。
内容来源于stack exchange

