This post shows how to get and set instance variables and invoke methods via the Reflection API using Spring ReflectionTestUtils. There are fundamental reasons to do things via Reflection: 1) test non-public methods (not recommended, though), and 2) inaccessible instance variables (to mock).
Java Class For Reflection Test
For our example, we’ll use the following simple class. Notice that the internalCode is inaccessible outside of the Student class. There is no way to access the properties except via Java Reflection API. Therefore, we could use the Reflection API in Spring, but we do not have to do it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class Student { private int internalCode; private String name; public void save() { System.out.println("public method - save"); saveOrUpdate("Awesome data!"); } private void saveOrUpdate(String someData) { System.out.println("private method - saveOrUpdate [" + someData +"]"); } public String getName(){ return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "internalCode=" + internalCode + ", name='" + name + '\'' + '}'; } } |
Nothing is preventing us from using the Reflection API. However, we may not want to create low-level (relatively speaking) codes. Instead, we can use Spring ReflectionTestUtils.
Test Reflection with Spring ReflectionTestUtils
Consider the following example codes that use Spring ReflectionTestUtils. We can use setField and getField methods to update and get property values, respectively.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @RunWith(SpringRunner.class) @SpringBootTest public class ComTurretaSpringReflectionReflectiontestutilsApplicationTests { @Test public void test01() { Student student = new Student(); student.setName("James Dean"); System.out.println("Before: " + student.toString()); ReflectionTestUtils.setField(student, "internalCode", 1343243); System.out.println("After: " + student.toString()); ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test"); } } |
Moreover, we can even call private methods using the invokeMethod method from the Spring ReflectionTestUtils. No need for Java Reflection API, right?
When we run the codes, we get the following output.
Our codes successfully updated the private field values using Spring ReflectionTestUtils. However, we do still use the Java Reflection API, but we use it indirectly because Spring ReflectionTestUtils uses the native API.