简体   繁体   中英

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. 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?

@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. So no need to use the ReflectionTestUtils.setField ; which will start failing in jdk-17 and up.


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.

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:

  • 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.

I normally use it for setting up some dummy domain objects which are JPA entities for testing. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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