我在服务中使用自动装配的构造函数,当在测试类中实例化时,会导致@Value注释返回null . 自动装配依赖项直接解决了问题,但项目遵循使用基于构造函数的自动装配的惯例 . 我的理解是,在测试类中实例化服务并不是从Spring IoC容器创建它,导致@Value返回null . 有没有办法使用基于构造函数的自动装配从IoC容器创建服务,而无需直接访问应用程序上下文?
示例服务:
@Component
public class UpdateService {
@Value("${update.success.table}")
private String successTable;
@Value("${update.failed.table}")
private String failedTable;
private UserService userService
@Autowired
public UpdateService(UserService userService) {
this.userService = userService;
}
}
示例测试服务:
@RunWith(SpringJUnite4ClassRunner.class)
@SpringApplicationConfiguration(classes = {TestApplication.class})
@WebAppConfiguration
public class UpdateServiceTest {
private UpdateService updateService;
@Mock
private UserService mockUserService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
updateService = new UpdateService(mockUserService);
}
}
2 回答
要使
@Value
工作updateService
应该在spring上下文中 .Spring框架集成测试的最佳实践是在测试环境中包含应用程序上下文,并在测试中包含自动装配测试源:
Mock userService
将
userService
更改为protected
的选项,并考虑测试和源类在同一个包中 .使用Whitebox反射的选项:
@Value
由属性占位符配置器填充,该配置器是 spring 上下文中的后处理器 . 由于您的UpdateService
不是上下文的一部分,因此不会进行处理 .您的设置看起来有点像单元和集成测试的不清楚的混合 . 对于单元测试,您根本不需要 spring 环境 . 只需使
@Value
带注释的成员包受到保护并设置它们或使用ReflectionTestUtils.setField()
(均显示):对于集成测试,所有接线应通过 spring 完成 .
为此,我添加了一个提供模拟用户服务的内部配置类(
@Primary
仅适用于您在上下文中有任何其他用户服务的情况),并且模拟存储在静态成员中,以便从中轻松访问模拟之后进行测试 .