Mockito测试抛出NullPointerException而非自定义ExitException问题
解决Mockito模拟CLI时出现NullPointerException的问题
看起来你在测试ApplicationRunner时遇到了预期外的NPE,而不是想要验证的ExitException。咱们一步步排查解决:
核心原因分析
最常见的问题是:你的ApplicationRunner实例没有正确关联到Mock出来的APUCLI对象,导致调用parse方法时,内部依赖的cli是null,触发了NullPointerException,根本没走到help()方法抛出自定义异常的逻辑。
解决方案步骤
1. 确保Mock实例注入到ApplicationRunner中
你需要把Mock的APUCLI关联到ApplicationRunner,有两种可靠方式:
方式1:使用@InjectMocks自动注入
Mockito会自动把@Mock标注的实例注入到@InjectMocks的对象中(支持构造器、setter或字段注入):
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.InjectMocks; import org.mockito.MockitoAnnotations; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.doThrow; public class ApplicationRunnerTest { @Mock private APUCLI cli; @InjectMocks private ApplicationRunner runner; @BeforeEach void setUp() { // 初始化Mockito注解(JUnit 5+如果用MockitoExtension可省略这行) MockitoAnnotations.openMocks(this); } @Test void testParseThrowsExitExceptionOnHelpCall() { // 先Stub CLI的help()方法,让它抛出自定义ExitException doThrow(new ExitException()).when(cli).help(); // 执行测试:触发parse方法调用help逻辑 assertThrows(ExitException.class, () -> runner.parse(new String[]{"--help"})); } }
方式2:手动构造注入(更直观)
如果ApplicationRunner有接收APUCLI的构造器,直接手动传入Mock实例:
@BeforeEach void setUp() { cli = Mockito.mock(APUCLI.class); runner = new ApplicationRunner(cli); // 手动关联mock对象 }
2. 检查Stub语法是否正确
因为help()是void方法,不能用普通的when(...).thenThrow语法(会触发实际调用导致意外问题),必须用doThrow来Stub:
// ✅ 正确的void方法Stub方式 doThrow(new ExitException()).when(cli).help(); // ❌ 错误方式:会实际调用cli.help(),可能触发NPE或其他异常 // Mockito.when(cli.help()).thenThrow(new ExitException());
3. 验证parse方法的触发逻辑
确保当你传入触发help的参数(比如--help)时,ApplicationRunner的parse方法确实会调用cli.help()。比如你的业务逻辑应该类似:
public class ApplicationRunner { private final APUCLI cli; public ApplicationRunner(APUCLI cli) { this.cli = cli; } public void parse(String[] args) { if (Arrays.asList(args).contains("--help")) { cli.help(); // 这里会触发mock的Stub逻辑,抛出ExitException } // 其他业务逻辑 } }
额外排查点
- 确认
ExitException是非受检异常(继承自RuntimeException),如果是受检异常,parse方法需要声明抛出,否则编译报错,也会导致测试异常。 - JUnit 5环境下,可以在测试类上添加
@ExtendWith(MockitoExtension.class),替代手动调用MockitoAnnotations.openMocks(this),简化初始化流程。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

