Spring Boot:ReflectionTestUtils.setFields 是如何工作的?
SpringBoot : How ReflectionTestUtils.setFields work?
考虑以下代码:
服务
class MyService{
@Autowired
private ModelMapper modelMapper;
void validate(){
ResponseObject obj = modelMapper.map( REQUEST, ResponseObject.class);
// In testing, if I am not mocking this Model Mapper, an exception will be thrown.
}
}
测试
在 JUnit 测试用例中,我没有使用模拟,而是使用 ReflectionTestUtils.setField("", "", "") 并进行映射正如预期的那样。但我不知道发生了什么以及它是如何工作的。我参考了很多资源,但我找不到任何可靠的资源。 谁能告诉我 ReflectionTestUtils 是什么,它是如何工作的,什么时候使用它?
@InjectMocks
MyService service;
private ModelMapper modelMapper;
@BeforeEach
void setup() {
modelMapper = new ModelMapper();
ReflectionTestUtils.setField( service, "modelMapper", modelMapper);
}
而不是非常反模式(如果你问我的话):
@Autowired
private ModelMapper modelMapper;
您始终可以通过构造函数注入它:
private final ModelMapper modelMapper;
class MyService(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
当 MyService
是 spring 知道的 bean 时,将为您自动装配。所以不需要使用 ReflectionTestUtils.setField
;这将在 jdk-17
及以后开始失败。
由于您现在通过构造函数传递它,因此使用模拟注入是微不足道的。
它在幕后使用反射API来设置对象字段的值。
关于何时使用它,documentation 已经提供了一些信息:
You can use these methods in testing scenarios where you need to
change the value of a constant, set a non-public field, invoke a
non-public setter method, or invoke a non-public configuration or
lifecycle callback method when testing application code for use cases
such as the following:
ORM frameworks (such as JPA and Hibernate) that condone private or
protected field access as opposed to public setter methods for
properties in a domain entity.
Spring’s support for annotations (such as @Autowired, @Inject, and
@Resource), that provide dependency injection for private or protected
fields, setter methods, and configuration methods.
Use of annotations such as @PostConstruct and @PreDestroy for
lifecycle callback methods.
我通常用它来设置一些虚拟域对象,这些对象是用于测试的 JPA 实体。由于它们的 ID 由 Hibernate 管理并具有良好的封装性,因此它们没有任何 setter 或构造函数来配置它们的 ID 值,因此需要使用它来为它们的 ID 设置一些虚拟值。
考虑以下代码:
服务
class MyService{
@Autowired
private ModelMapper modelMapper;
void validate(){
ResponseObject obj = modelMapper.map( REQUEST, ResponseObject.class);
// In testing, if I am not mocking this Model Mapper, an exception will be thrown.
}
}
测试
在 JUnit 测试用例中,我没有使用模拟,而是使用 ReflectionTestUtils.setField("", "", "") 并进行映射正如预期的那样。但我不知道发生了什么以及它是如何工作的。我参考了很多资源,但我找不到任何可靠的资源。 谁能告诉我 ReflectionTestUtils 是什么,它是如何工作的,什么时候使用它?
@InjectMocks
MyService service;
private ModelMapper modelMapper;
@BeforeEach
void setup() {
modelMapper = new ModelMapper();
ReflectionTestUtils.setField( service, "modelMapper", modelMapper);
}
而不是非常反模式(如果你问我的话):
@Autowired
private ModelMapper modelMapper;
您始终可以通过构造函数注入它:
private final ModelMapper modelMapper;
class MyService(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
当 MyService
是 spring 知道的 bean 时,将为您自动装配。所以不需要使用 ReflectionTestUtils.setField
;这将在 jdk-17
及以后开始失败。
由于您现在通过构造函数传递它,因此使用模拟注入是微不足道的。
它在幕后使用反射API来设置对象字段的值。
关于何时使用它,documentation 已经提供了一些信息:
You can use these methods in testing scenarios where you need to change the value of a constant, set a non-public field, invoke a non-public setter method, or invoke a non-public configuration or lifecycle callback method when testing application code for use cases such as the following:
ORM frameworks (such as JPA and Hibernate) that condone private or protected field access as opposed to public setter methods for properties in a domain entity.
Spring’s support for annotations (such as @Autowired, @Inject, and @Resource), that provide dependency injection for private or protected fields, setter methods, and configuration methods.
Use of annotations such as @PostConstruct and @PreDestroy for lifecycle callback methods.
我通常用它来设置一些虚拟域对象,这些对象是用于测试的 JPA 实体。由于它们的 ID 由 Hibernate 管理并具有良好的封装性,因此它们没有任何 setter 或构造函数来配置它们的 ID 值,因此需要使用它来为它们的 ID 设置一些虚拟值。