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

夙愿已清 提交于 2019-12-06 03:24:21
cahen

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;
    }
}

You could go lo-fi and create a sub-class of the DBClient class. To this subclass, pass the instance of DBClient you want to mock.

Use composition inside the sub-class, and delegate all method calls to the original DBClient, all except the one you want to mock. Add your mock implementation to the method you want.

This is not as reusable as a mocking framework, but should work.

DBClient mockDbClient = new DBClient() {
     private DBClient dbClientDelegate;

     public void setDelegate(DBClient dbClient) {
         dbClientDelegate = dbClient;
    }

    //override all methods. 
    //delegate to the corresponding method of the dbClientDelegate instance

    //overide the method you want to mock, add asserts for method arguments
    //return mock data as appropriate

}

mockDbClient.setDelegate(preinstantiatedDbClient);
//inject mockDbClient to test class
//call test class / method

Hope this helps.

In Mockito 2+ you can use spy feature for this purpose:

    PrintStream realSystemOut = System.out;
    realSystemOut.println("XXX");

    PrintStream mockedSystemOut = Mockito.spy(realSystemOut);
    Mockito.doNothing().when(mockedSystemOut).println(Mockito.anyString());
    mockedSystemOut.println("YYY");

Output:

XXX
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!