简体   繁体   English

SpringBoot:ReflectionTestUtils.setFields 是如何工作的?

[英]SpringBoot : How ReflectionTestUtils.setFields work?

Consider the below code:考虑下面的代码:

Service服务

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.

  }

}

Testing测试

Here in JUnit test cases, instead of mocking, I am making use of ReflectionTestUtils.setField("", "", "") and the mapping takes place as expected.在 JUnit 测试用例中,我使用的是ReflectionTestUtils.setField("", "", "")而不是 mocking,并且映射按预期进行。 But I am not aware of what's happening and how it's working.但我不知道发生了什么以及它是如何工作的。 I referred to many sources, but I couldn't find any reliable resource regarding this.我参考了许多来源,但我找不到任何可靠的资源。 Can someone tell me whats ReflectionTestUtils, how its works, and when to use it?谁能告诉我 ReflectionTestUtils 是什么,它是如何工作的,以及何时使用它?

@InjectMocks
MyService service;

private ModelMapper modelMapper;

@BeforeEach
void setup() {
    modelMapper = new ModelMapper();
    ReflectionTestUtils.setField( service, "modelMapper", modelMapper);

}

Instead of doing the very anti-pattern (if you ask me):而不是做非常反模式(如果你问我):

@Autowired
private ModelMapper modelMapper;

you can always inject it via the constructor:你总是可以通过构造函数注入它:

private final ModelMapper modelMapper;

class MyService(ModelMapper modelMapper) {
    this.modelMapper = modelMapper;
}

when MyService is a bean that spring is aware of, the auto-wiring will happen for you.MyService是 spring 知道的 bean 时,自动装配将为您发生。 So no need to use the ReflectionTestUtils.setField ;所以不需要使用ReflectionTestUtils.setField which will start failing in jdk-17 and up.这将在jdk-17及更高版本中开始失败。


Since you now pass it via a constructor, injection with a mock for example, is trivial.由于您现在通过构造函数传递它,因此使用模拟注入是微不足道的。

It uses reflection API under the cover to set the value for an object 's field.它在封面下使用反射 API 来设置 object 字段的值。

About when to use it, the documentation already provides some info:关于何时使用它, 文档已经提供了一些信息:

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:您可以在需要更改常量值、设置非公共字段、调用非公共 setter 方法或在测试应用程序代码时调用非公共配置或生命周期回调方法的测试场景中使用这些方法。用例如下:

  • 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. ORM 框架(例如 JPA 和 Hibernate)允许私有或受保护的字段访问,而不是域实体中属性的公共设置方法。

  • 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. Spring 对注解(如@Autowired、@Inject 和@Resource)的支持,为私有或受保护字段、setter 方法和配置方法提供依赖注入。

  • Use of annotations such as @PostConstruct and @PreDestroy for lifecycle callback methods.对生命周期回调方法使用 @PostConstruct 和 @PreDestroy 等注解。

I normally use it for setting up some dummy domain objects which are JPA entities for testing.我通常用它来设置一些虚拟域对象,这些对象是 JPA 实体进行测试。 Since their ID are managed by Hibernate and to have a good encapsulation, they do not have any setter or constructor to configure their ID value, and hence need to use it to setup some dummy values for their ID.由于它们的 ID 由 Hibernate 管理并具有良好的封装性,因此它们没有任何 setter 或构造函数来配置其 ID 值,因此需要使用它来为其 ID 设置一些虚拟值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM