Mocking member variables of a class using Mockito

前端 未结 9 1797
醉话见心
醉话见心 2020-12-07 10:24

I am a newbie to development and to unit tests in particular . I guess my requirement is pretty simple, but I am keen to know others thoughts on this.

Suppose I h

9条回答
  •  时光取名叫无心
    2020-12-07 10:33

    I had the same issue where a private value was not set because Mockito does not call super constructors. Here is how I augment mocking with reflection.

    First, I created a TestUtils class that contains many helpful utils including these reflection methods. Reflection access is a bit wonky to implement each time. I created these methods to test code on projects that, for one reason or another, had no mocking package and I was not invited to include it.

    public class TestUtils {
        // get a static class value
        public static Object reflectValue(Class classToReflect, String fieldNameValueToFetch) {
            try {
                Field reflectField  = reflectField(classToReflect, fieldNameValueToFetch);
                reflectField.setAccessible(true);
                Object reflectValue = reflectField.get(classToReflect);
                return reflectValue;
            } catch (Exception e) {
                fail("Failed to reflect "+fieldNameValueToFetch);
            }
            return null;
        }
        // get an instance value
        public static Object reflectValue(Object objToReflect, String fieldNameValueToFetch) {
            try {
                Field reflectField  = reflectField(objToReflect.getClass(), fieldNameValueToFetch);
                Object reflectValue = reflectField.get(objToReflect);
                return reflectValue;
            } catch (Exception e) {
                fail("Failed to reflect "+fieldNameValueToFetch);
            }
            return null;
        }
        // find a field in the class tree
        public static Field reflectField(Class classToReflect, String fieldNameValueToFetch) {
            try {
                Field reflectField = null;
                Class classForReflect = classToReflect;
                do {
                    try {
                        reflectField = classForReflect.getDeclaredField(fieldNameValueToFetch);
                    } catch (NoSuchFieldException e) {
                        classForReflect = classForReflect.getSuperclass();
                    }
                } while (reflectField==null || classForReflect==null);
                reflectField.setAccessible(true);
                return reflectField;
            } catch (Exception e) {
                fail("Failed to reflect "+fieldNameValueToFetch +" from "+ classToReflect);
            }
            return null;
        }
        // set a value with no setter
        public static void refectSetValue(Object objToReflect, String fieldNameToSet, Object valueToSet) {
            try {
                Field reflectField  = reflectField(objToReflect.getClass(), fieldNameToSet);
                reflectField.set(objToReflect, valueToSet);
            } catch (Exception e) {
                fail("Failed to reflectively set "+ fieldNameToSet +"="+ valueToSet);
            }
        }
    
    }
    

    Then I can test the class with a private variable like this. This is useful for mocking deep in class trees that you have no control as well.

    @Test
    public void testWithRectiveMock() throws Exception {
        // mock the base class using Mockito
        ClassToMock mock = Mockito.mock(ClassToMock.class);
        TestUtils.refectSetValue(mock, "privateVariable", "newValue");
        // and this does not prevent normal mocking
        Mockito.when(mock.somthingElse()).thenReturn("anotherThing");
        // ... then do your asserts
    }
    

    I modified my code from my actual project here, in page. There could be a compile issue or two. I think you get the general idea. Feel free to grab the code and use it if you find it useful.

提交回复
热议问题