Mocking getClass method with PowerMockito

后端 未结 3 562
逝去的感伤
逝去的感伤 2020-12-19 05:18

I\'d like to avoid mocking the getClass() method for a class but cannot seem to find any way around it. I\'m trying to test a class that stores objects class types in a Hash

3条回答
  •  时光取名叫无心
    2020-12-19 06:01

    Wow, what a headache to get this code testable. The main issues are that you can't use mock objects as key objects into your calls to map.get(obj.getClass()), and you're trying to invoke() potentially mock objects for your testing. I had to refactor your class under test so that we can mock out the functionality/behaviour and be able to verify its behaviour.

    So this is your new implementation to be tested with member variables decoupling the various pieces of functionailty and injected by the test class

    public class ClassToTest {
    
        MethodStore methodStore;
        MethodInvoker methodInvoker;
        ClassToInvoke classToInvoke;
        ObjectRunner objectRunner;  
    
        public void testMethod(InterfaceA obj) throws Exception {
    
            Method method = methodStore.getMethod(obj);
    
            boolean ok = false;
    
            if (method != null) {
                ok = methodInvoker.invoke(method, classToInvoke, obj);
            }
    
            if (ok) {
                objectRunner.run(obj);
            }   
        }
    
        public void setMethodStore(MethodStore methodStore) {
            this.methodStore = methodStore;
        }
    
        public void setMethodInvoker(MethodInvoker methodInvoker) {
            this.methodInvoker = methodInvoker;
        }
    
        public void setObjectRunner(ObjectRunner objectRunner) {
            this.objectRunner = objectRunner;
        }
    
        public void setClassToInvoke(ClassToInvoke classToInvoke) {
            this.classToInvoke = classToInvoke;
        }
    }
    

    This is your test class that no longer requires PowerMock, because it can't mock the Method class. It just returns a NullPointerException.

    public class MyTest {
    
        @Test
        public void test() throws Exception {
    
            ClassToTest classToTest = new ClassToTest();
    
            ClassA inputA = new ClassA();
    
            // trying to use powermock here just returns a NullPointerException
    //      final Method mockMethod = PowerMockito.mock(Method.class);
            Method mockMethod = (new ClassToInvoke()).getClass().getMethod("someMethod");   // a real Method instance
    
            // regular mockito for mocking behaviour    
            ClassToInvoke mockClassToInvoke = mock(ClassToInvoke.class);
            classToTest.setClassToInvoke(mockClassToInvoke);
    
            MethodStore mockMethodStore = mock(MethodStore.class);
            classToTest.setMethodStore(mockMethodStore);
    
            when(mockMethodStore.getMethod(inputA)).thenReturn(mockMethod);
    
            MethodInvoker mockMethodInvoker = mock(MethodInvoker.class);
            classToTest.setMethodInvoker(mockMethodInvoker);
    
            when(mockMethodInvoker.invoke(mockMethod,mockClassToInvoke, inputA)).thenReturn(Boolean.TRUE);
    
            ObjectRunner mockObjectRunner = mock(ObjectRunner.class);
            classToTest.setObjectRunner(mockObjectRunner);
    
            // execute test method      
            classToTest.testMethod(inputA);
    
            verify(mockObjectRunner).run(inputA);   
        }
    }
    

    The additional classes you require are as follows

    public class ClassToInvoke {
        public void someMethod() {};
    }
    
    public class ClassA implements InterfaceA {
    
        @Override
        public void run() {
            // do something
        }
    }
    
    public class ClassToInvoke {
        public void someMethod() {};
    }
    
    public class MethodInvoker {
    
        public Boolean invoke(Method method, Object obj, InterfaceA a) throws Exception {
             return (Boolean) method.invoke(obj, a);
        }
    }
    
    public class MethodStore {
    
        Map, Method> map = new HashMap, Method>();
    
        public Method getMethod(InterfaceA obj) {
            return map.get(obj);
        }
    }
    

    Put all this into your IDE and it will pass with a Green bar...woohoo!

提交回复
热议问题