单元测试遇InvalidUseOfMatchersException及空指针问题求助
问题分析与解决方案
第一个错误:InvalidUseOfMatchersException
原因
- 混合使用参数匹配器与具体值:你对
nonSettle方法设置返回值时,同时用了Mockito.any(LocalDate.class)(参数匹配器)和LocalDate.of(2021,12,24)(具体参数),Mockito禁止这种混合写法,要么全用匹配器,要么全用具体值。 - 未使用Spy mock类内部方法:
@InjectMocks创建的是真实对象,不能直接用Mockito.when()来mock它的方法,必须用@Spy包装真实对象才能实现类内部方法的mock。
解决方案
- 将
@InjectMocks替换为@Spy并初始化真实对象:
@Spy private CalculateDateService tested = new CalculateDateService();
- 用
doReturn替代when(避免触发真实方法执行),先设置默认规则,再覆盖特定日期:
// 所有日期默认返回false(非结算日) doReturn(false).when(tested).nonSettle(Mockito.any(LocalDate.class)); // 特定日期2021-12-24返回true(结算日) doReturn(true).when(tested).nonSettle(LocalDate.of(2021, 12, 24));
第二个错误:NullPointerException
原因
你用@InjectMocks的真实对象调用Mockito.when(tested.nonSettle(...))时,会先执行真实的nonSettle方法。如果测试环境中LocalDate.now()被意外mock为null,或是因未用Spy导致真实方法执行时触发了未预期的逻辑,就会在LocalDate.of(year, 12, 24)行抛出NPE。
解决方案
- 采用上面的
@Spy + doReturn写法,直接设置返回值,跳过真实方法的执行,从根源避免NPE。 - 如果需要测试真实的
nonSettle逻辑,可通过PowerMock固定LocalDate.now()的返回值(需引入PowerMock依赖):
PowerMockito.mockStatic(LocalDate.class); Mockito.when(LocalDate.now()).thenReturn(LocalDate.of(2021, 1, 1));
完整测试代码示例
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import java.time.LocalDate; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.any; @RunWith(MockitoJUnitRunner.class) public class CalculateDateServiceTest { @Spy private CalculateDateService tested = new CalculateDateService(); @Test public void testRollDays() { // 设置默认规则 doReturn(false).when(tested).nonSettle(any(LocalDate.class)); // 覆盖特定日期规则 doReturn(true).when(tested).nonSettle(LocalDate.of(2021, 12, 24)); // 注意补全rollDays方法的第三个参数 LocalDate result = tested.rollDays(2, LocalDate.of(2021, 12, 22), "mar"); LocalDate correctRolledDate = LocalDate.of(2021, 12, 25); assertEquals(result, correctRolledDate); } }
内容的提问来源于stack exchange,提问作者w97802
相关产品推荐
相关产品推荐

