JUnit测试无法@Autowired注入Service类但Controller中注入正常如何解决?
问题根本原因
@DataJpaTest 是Spring Boot提供的切片测试注解,默认仅加载JPA相关组件(Repository、EntityManager等),不会扫描并注册@Service注解的业务层Bean,因此测试类中无法注入UserService实例。而你启动完整Web应用时会扫描全量组件,所以Controller层注入可以正常生效。
可行解决方案
- 方案1:添加@Import注解手动导入UserService
直接在测试类上新增@Import(UserService.class),手动将UserService注册到测试上下文。同时你需要注意UserService依赖的PasswordEncoder也需要在测试上下文中存在,否则会报新的找不到Bean错误,可以在测试类中额外声明一个PasswordEncoder的测试Bean:
示例修改后的测试类代码:package com.crmbackend.user; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import com.crmbackend.entity.Role; import com.crmbackend.entity.User; import com.crmbackend.userService.UserService; @DataJpaTest(showSql = true) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Rollback(false) @Import(UserService.class) // 手动导入UserService public class UserServiceTests { // 测试类内部声明测试用PasswordEncoder @TestConfiguration static class TestConfig { @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } @Autowired private TestEntityManager entityManager; @Autowired private UserService service; @Test public void testCreateNewUserWithSingleRolePasswordEncode() { Role roleUser = entityManager.find(Role.class, 3); User userLucas = new User("lucas9324", "Lucas", "Tom", "qqq542417349", "Lucas9324@outlook.com", "7364832234"); userLucas.addRole(roleUser); User savedUser = service.save(userLucas); assertThat(savedUser.getId()).isGreaterThan(0); } } - 方案2:改用@SpringBootTest注解加载全量上下文
如果需要加载完整的Spring应用上下文进行集成测试,把@DataJpaTest替换为@SpringBootTest即可,该注解会扫描所有标注了Spring组件注解的类,和你启动正式应用的上下文一致,无需额外导入Bean。缺点是测试启动速度会比切片测试慢。
示例修改后的测试类注解部分:@SpringBootTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Rollback(false) public class UserServiceTests { // 原有测试代码保持不变 }
内容的提问来源于stack exchange,提问作者PEIRAN LIU
相关产品推荐
相关产品推荐

