Using Reflection for Testing
I am working on a presentation about the ‘Single Responsibility Principle’, based on my previous post. It take most of my time.
In the meantime, I want to share a sample code of how I use to test inner fields in my classes. I am doing it for a special case of testing, which is more of an integration test. In the standard unit testing of the dependent class, I am using mocks of the dependencies.
The Facts
- All of the fields (and dependencies in our classes are private
- The class do not have getters for its dependencies
- We wire things up using Spring (XML context)
- I wan to verify that dependency interface A is wired correctly to dependent class B
One approach would be to wire everything and then run some kind of integration test of the logic. I don’t want to do this. It will make the test hard to maintain.
The other approach is to check wiring directly. And for that I am using reflection.
Below is a sample code of the testing method, and the usage. Notice how I am catching the exception and throws a RuntimeException in case there is a problem. This way, I have cleaner tested code.
// Somewhere in a different utility class for testing @SuppressWarnings("unchecked") public static <T> T realObjectFromField(Class<?> clazz, String fieldName, Object object) { Field declaredField = accessibleField(clazz, fieldName); try { return (T) declaredField.get(object); } catch (IllegalArgumentException | IllegalAccessException e) { throw new RuntimeException(e); } } private static Field accessibleField(Class<?> clazz, String fieldName) { try { Field declaredField = clazz.getDeclaredField(fieldName); declaredField.setAccessible(true); return declaredField; } catch (NoSuchFieldException | SecurityException e) { throw new RuntimeException(e); } } // This is how we use it in a test method import static mypackage.ReflectionUtils.realObjectFromField; ItemFiltersMapperByFlag mapper = realObjectFromField(ItemsFilterExecutor.class, "filtersMapper", filterExecutor); assertNotNull("mapper is null. Check wiring", mapper);