单元测试中如何在注入服务类构造函数执行前模拟值?
问题分析
你的核心问题是Spring上下文初始化时会优先创建MyService实例并执行构造函数,而@BeforeEach注解的init()方法是在MyService实例化完成后、测试方法执行前才运行,导致mockValue()设置的模拟值无法被构造函数中的myRepository.getValue()获取,最终触发空值异常。
解决方案
方案1:手动创建Mock与实例(推荐,测试效率更高)
完全脱离Spring自动注入,直接用Mockito创建MyRepository的Mock对象,在实例化MyService之前就设置好模拟返回值,彻底控制初始化顺序:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; class MyServiceTest { private MyService myService; private MyRepository mockMyRepository; @BeforeEach void init() { // 创建MyRepository的Mock对象 mockMyRepository = mock(MyRepository.class); // 在实例化MyService前设置模拟值 when(mockMyRepository.getValue("login")).thenReturn("login_value"); when(mockMyRepository.getValue("password")).thenReturn("password_value"); // 手动初始化MyService myService = new MyService(mockMyRepository); } // 编写你的测试方法... }
这种方式不需要启动Spring上下文,测试执行速度更快,且完全避免了Spring初始化顺序带来的问题。
方案2:通过测试配置类提前准备Mock(依赖Spring上下文场景)
如果必须依赖Spring上下文进行测试,可以自定义测试配置类,在配置类中提前创建并配置好MyRepository的Mock对象,确保MyService构造函数执行时能拿到有效模拟值:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @ContextConfiguration(classes = MyServiceTest.TestConfig.class) class MyServiceTest { @Autowired private MyService myService; // 自定义测试配置类 @Configuration static class TestConfig { @Bean public MyRepository myRepository() { MyRepository mockRepo = mock(MyRepository.class); // 提前设置模拟返回值 when(mockRepo.getValue("login")).thenReturn("login_value"); when(mockRepo.getValue("password")).thenReturn("password_value"); return mockRepo; } @Bean public MyService myService(MyRepository myRepository) { return new MyService(myRepository); } } // 编写你的测试方法... }
Spring上下文初始化时,会先加载TestConfig中的MyRepository Bean,此时模拟值已经设置完成,后续创建MyService时构造函数就能正常获取到值。
内容的提问来源于stack exchange,提问作者Laziz
相关产品推荐
相关产品推荐

