Skip to content

Instantly share code, notes, and snippets.

@peichhorn
Created July 2, 2012 16:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peichhorn/3034237 to your computer and use it in GitHub Desktop.
Save peichhorn/3034237 to your computer and use it in GitHub Desktop.
Tiny mocking framework (less that 100 LOC) that I've used to demonstrate dynamic proxies.
/*
* Copyright © 2012 Philipp Eichhorn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.fips.util.tinymock;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
/**
* <p>Mockito-ish API for simple Mocks of no argument methods, like getters.</p>
* <p>Since this implementation uses the {@link Proxy Dynamic-Proxy} API, it will only work with interfaces.</p>
* <p><pre>
* IDeepThought deepThought = TinyMock.mock(IDeepThought.class);
* TinyMock.doReturn("42").when(deepThought).getAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything();
* </pre></p>
*
* @author Philipp Eichhorn
*/
final class TinyMock {
private TinyMock() {
super();
}
/** */
@SuppressWarnings("unchecked")
public static <INTERFACE_TYPE, TYPE extends INTERFACE_TYPE> TYPE mock(final Class<INTERFACE_TYPE> interfaceType) {
return (TYPE) Proxy.newProxyInstance(TinyMock.class.getClassLoader(), new Class[] { interfaceType }, new Stubs(interfaceType));
}
/** */
public static OngoingStubbing doReturn(final Object returnValue) {
return new OngoingStubbing(returnValue);
}
/** */
public final static class OngoingStubbing {
private final Object _returnValue;
private OngoingStubbing(final Object returnValue) {
_returnValue = returnValue;
}
/** */
@SuppressWarnings("unchecked")
public <INTERFACE_TYPE> INTERFACE_TYPE when(final INTERFACE_TYPE mock) {
final InvocationHandler invocationHandler = Proxy.getInvocationHandler(mock);
if (!(invocationHandler instanceof Stubs)) {
throw new IllegalArgumentException("The given object is not a mock.");
}
final Stubs stubs = (Stubs) invocationHandler;
return (INTERFACE_TYPE) Proxy.newProxyInstance(TinyMock.class.getClassLoader(), new Class[] { stubs.getInterfaceType() }, new Stubbing(stubs, _returnValue));
}
}
private static class Stubbing implements InvocationHandler {
private final Stubs _stubs;
private final Object _returnValue;
private Stubbing(final Stubs stubs, final Object returnValue) {
_stubs = stubs;
_returnValue = returnValue;
}
public final Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
_stubs.addStub(method.getName(), _returnValue);
return null;
}
}
private static class Stubs implements InvocationHandler {
private final Map<String, Object> _stubs = new HashMap<String, Object>();
private final Class<?> _interfaceType;
private Stubs(final Class<?> interfaceType) {
_interfaceType = interfaceType;
}
public Class<?> getInterfaceType() {
return _interfaceType;
}
public void addStub(final String methodName, final Object returnValue) {
_stubs.put(methodName, returnValue);
}
public final Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final Object object = _stubs.get(method.getName());
if ((object != null) && (args == null)) {
return object;
} else {
return null;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment