Skip to content

Instantly share code, notes, and snippets.

@ondrej-kvasnovsky
Created January 10, 2024 04:25
Show Gist options
  • Save ondrej-kvasnovsky/c57bdfae8220a06f8354cef7678cb98b to your computer and use it in GitHub Desktop.
Save ondrej-kvasnovsky/c57bdfae8220a06f8354cef7678cb98b to your computer and use it in GitHub Desktop.
Mocker
package com.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Mocker implements InvocationHandler {
private static final Mocker handler = new Mocker();
public static <T> T createMock(Class<T> clazz) {
Class<?> proxyClass = Proxy.newProxyInstance(
clazz.getClassLoader(),
new Class[]{clazz},
handler
)
.getClass();
try {
return (T) proxyClass
.getConstructor(new Class[]{InvocationHandler.class})
.newInstance(new Object[]{handler});
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private static final ThreadLocal<Method> methodThreadLocal = new ThreadLocal<>();
private static final Map<String, Object> methodToReturnValue = new HashMap<>();
public Object invoke(Object proxy, Method method, Object[] args) {
// when they call when(obj.getSomething)), we register it as a mocked method we are mocking at this point
methodThreadLocal.set(method);
if (methodToReturnValue.containsKey(method.getName())) {
return methodToReturnValue.get(method.getName());
}
return null;
}
public static <T> OngoingMocking<T> when(T methodCall) {
return new OngoingMocking<>();
}
public static class OngoingMocking<T> {
public void thenReturn(T value) {
Method method = methodThreadLocal.get();
methodThreadLocal.remove();
methodToReturnValue.put(method.getName(), value);
}
}
public static void main(String[] args) {
ItemService userServiceMock = Mocker.createMock(ItemService.class);
when(userServiceMock.fetch(1))
.thenReturn(new Item("An item returned from mocked service"));
when(userServiceMock.fetchAll())
.thenReturn(List.of(
new Item("Item 1"),
new Item("Item 2")
));
Controller controller = new Controller(userServiceMock);
Item item = controller.fetch(1);
System.out.println("A mocked item: " + item);
List<Item> items = controller.fetchAll();
System.out.println("Mocked items: " + items);
}
}
record Item(String name) {
}
interface ItemService {
Item fetch(int id);
List<Item> fetchAll();
}
class Controller {
private final ItemService itemService;
public Controller(ItemService itemService) {
this.itemService = itemService;
}
public Item fetch(int id) {
return itemService.fetch(id);
}
public List<Item> fetchAll() {
return itemService.fetchAll();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment