Search code examples
javaeasymockpowermockwhite-box

Is it possible to mock a single method in an already existing object?


For an integration test, I need to mock a specific method in a java service client without destroying the rest of the information in it. It has no self-constructor, so a solution like this is out of the question:

private DBClient mockClient = new DBClient(alreadyExistingClient){
    @Override
    void deleteItem(Item i){
        //my stuff goes here
    }
};

Is there a way to mock the deleteItem method such that the credentials, endpoints, etc... are preserved in an existing DBClient object?

edit: mockito is not available for use in this case


Solution

  • You can use a Dynamic Proxy to intercept any method invocation you want, so you can decide between invoking the real method or do whatever you want instead.

    This is an example of how to intercept the method Set.add(), you can do exactly the same for deleteItem()

    package example.dynamicproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Set;
    
    public class SetProxyFactory {
    
        public static Set<?> getSetProxy(final Set<?> s) {
            final ClassLoader classLoader = s.getClass().getClassLoader();
            final Class<?>[] interfaces = new Class[] {Set.class};
            final InvocationHandler invocationHandler = new InvocationHandler() {
    
                @Override
                public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
    
                    if (method.getName().equals("add")) {
                        System.out.println("add() intercepted");
                        // do/return whatever you want
                    }
    
                    // or invoke the real method
                    return method.invoke(s, args);
                }
            };
    
            final Object proxy = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    
            return (Set<?>) proxy;
        }
    }