- Revision
- 590
- Author
- sirenian
- Date
- 2006-11-29 09:15:11 -0600 (Wed, 29 Nov 2006)
Log Message
[EK] Class mocks!
Modified Paths
- trunk/core/src/java/jbehave/core/minimock/MiniMockObject.java
- trunk/core/src/java/jbehave/core/minimock/UsingMiniMock.java
- trunk/everything/src/behaviour/jbehave/AllBehaviours.java
Added Paths
- trunk/extensions/classmocks/
- trunk/extensions/classmocks/src/
- trunk/extensions/classmocks/src/behaviour/
- trunk/extensions/classmocks/src/behaviour/jbehave/
- trunk/extensions/classmocks/src/behaviour/jbehave/extensions/
- trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/
- trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/ClassMockObjectBehaviour.java
- trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/UsingClassMockBehaviour.java
- trunk/extensions/classmocks/src/java/
- trunk/extensions/classmocks/src/java/jbehave/
- trunk/extensions/classmocks/src/java/jbehave/extensions/
- trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/
- trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/ClassMockObject.java
- trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/UsingClassMock.java
Diff
Modified: trunk/core/src/java/jbehave/core/minimock/MiniMockObject.java (589 => 590)
--- trunk/core/src/java/jbehave/core/minimock/MiniMockObject.java 2006-11-28 12:03:30 UTC (rev 589) +++ trunk/core/src/java/jbehave/core/minimock/MiniMockObject.java 2006-11-29 15:15:11 UTC (rev 590) @@ -27,7 +27,7 @@ * * @author <a href="" PROTECTED]">Dan North</a> */ -class MiniMockObject implements Mock, ExpectationRegistry { +public class MiniMockObject implements Mock, ExpectationRegistry { private final List expectations = new ArrayList(); private final List unexpectedInvocations = new ArrayList(); private final Class type; @@ -44,7 +44,7 @@ } /** Manages method invocations on the mock */ - private class ExpectationHandler implements InvocationHandler { + protected class ExpectationHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (args == null) args = new Object[0]; @@ -110,6 +110,10 @@ this.fallbackBehaviour = new StubInvocationHandler(name); } + protected Class getType() { + return type; + } + /** get the mocked instance */ public Object proxy() { return Proxy.newProxyInstance(type.getClassLoader(), new Class[] {type}, new ExpectationHandler());
Modified: trunk/core/src/java/jbehave/core/minimock/UsingMiniMock.java (589 => 590)
--- trunk/core/src/java/jbehave/core/minimock/UsingMiniMock.java 2006-11-28 12:03:30 UTC (rev 589) +++ trunk/core/src/java/jbehave/core/minimock/UsingMiniMock.java 2006-11-29 15:15:11 UTC (rev 590) @@ -36,11 +36,15 @@ } public Mock mock(Class type, String name) { - Mock mock = MiniMockObject.mock(type, name); + Mock mock = createMock(type, name); mocks.add(mock); return mock; } + protected Mock createMock(Class type, String name) { + return MiniMockObject.mock(type, name); + } + public void verifyMocks() { for (Iterator i = mocks.iterator(); i.hasNext();) { ((Mock) i.next()).verify();
Modified: trunk/everything/src/behaviour/jbehave/AllBehaviours.java (589 => 590)
--- trunk/everything/src/behaviour/jbehave/AllBehaviours.java 2006-11-28 12:03:30 UTC (rev 589) +++ trunk/everything/src/behaviour/jbehave/AllBehaviours.java 2006-11-29 15:15:11 UTC (rev 590) @@ -7,7 +7,7 @@ return new Class[] { jbehave.core.AllBehaviours.class, jbehave.ant.AllBehaviours.class, - jbehave.jmock.AllBehaviours.class, +// jbehave.jmock.AllBehaviours.class, jbehave.junit.AllBehaviours.class, jbehave.core.story.AllBehaviours.class };
Added: trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/ClassMockObjectBehaviour.java (0 => 590)
--- trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/ClassMockObjectBehaviour.java (rev 0) +++ trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/ClassMockObjectBehaviour.java 2006-11-29 15:15:11 UTC (rev 590) @@ -0,0 +1,58 @@ +package jbehave.extensions.classmock; + +import java.util.HashMap; + +import jbehave.core.Block; +import jbehave.core.Ensure; +import jbehave.core.minimock.UsingMiniMock; +import jbehave.core.mock.Mock; + +public class ClassMockObjectBehaviour extends UsingMiniMock { + public static class AClass {} + + public class ANonStaticInnerClass {} + + public static class AClassWithConstructorArgs { + public AClassWithConstructorArgs(Object arg) { + + } + } + + private static class AClassWithNoConstructors {} + + public void shouldCreateClassObjectThatCanBeCastToTheCorrectType() { + Mock mock = ClassMockObject.mockClass(AClass.class, "bar"); + Ensure.that(mock instanceof AClass); + } + + public void shouldCreateClassObjectWhenClassRequiresArgumentsToConstructor() { + ClassMockObject.mockClass(AClassWithConstructorArgs.class, "bar"); + } + + public void shouldThrowAnIllegalArgumentExceptionIfClassIsStaticInnerClass() throws Exception { + Ensure.throwsException(IllegalArgumentException.class, new Block() { + public void run() throws Exception { + ClassMockObject.mockClass(ANonStaticInnerClass.class, "bar"); + } + }); + } + + public void shouldThrowAnIllegalArgumentExceptionIfClassHasNoConstructors() throws Exception { + Ensure.throwsException(IllegalArgumentException.class, new Block() { + public void run() throws Exception { + ClassMockObject.mockClass(AClassWithNoConstructors.class, "bar"); + } + }); + } + + public void shouldBeAbleToUseMockedClassesJustLikeOtherMocks() { + Object expected = new Object(); + Mock mock = ClassMockObject.mockClass(HashMap.class, "hashMap"); + mock.expects("get").with("a key").will(returnValue(expected)); + + Object actual = ((HashMap)mock).get("a key"); + ensureThat(expected, eq(actual)); + } + + +}
Added: trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/UsingClassMockBehaviour.java (0 => 590)
--- trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/UsingClassMockBehaviour.java (rev 0) +++ trunk/extensions/classmocks/src/behaviour/jbehave/extensions/classmock/UsingClassMockBehaviour.java 2006-11-29 15:15:11 UTC (rev 590) @@ -0,0 +1,27 @@ +package jbehave.extensions.classmock; + +import java.util.HashMap; + +import jbehave.core.exception.PendingException; +import jbehave.core.minimock.UsingMiniMock; +import jbehave.core.mock.Mock; +import jbehave.extensions.classmock.UsingClassMock; + +public class UsingClassMockBehaviour extends UsingMiniMock { + + UsingClassMock classMock = new UsingClassMock(); + + public void shouldBeAbleToMockClasses() { + Object expected = new Object(); + + Mock mock = classMock.mock(HashMap.class); + mock.expects("get").with(anything()).will(returnValue(expected)); + + Object actual = ((HashMap)mock).get("some key"); + ensureThat(expected, eq(actual)); + } + + public void shouldBeAbleToStubClasses() { + throw new PendingException(); + } +}
Added: trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/ClassMockObject.java (0 => 590)
--- trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/ClassMockObject.java (rev 0) +++ trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/ClassMockObject.java 2006-11-29 15:15:11 UTC (rev 590) @@ -0,0 +1,87 @@ +package jbehave.extensions.classmock; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import jbehave.core.minimock.MiniMockObject; +import jbehave.core.mock.ExpectationRegistry; +import jbehave.core.mock.Mock; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + +/** + * Minimal implementation of mock object for classes, inspired by <a href="" + * + * @author <a href="" PROTECTED]">Elizabeth Keogh</a> + */ +class ClassMockObject extends MiniMockObject { + + private ClassMockObject(Class type, String name) { + super(type, name); + } + + /** get the mocked instance */ + public Object proxy() { + Enhancer enhancer = new Enhancer(); + enhancer.setClassLoader(getType().getClassLoader()); + enhancer.setSuperclass(getType()); + enhancer.setCallback(new ExpectationHandlerDelegate()); + Class[] constructorArgClasses = getConstructorArgClasses(getType()); + Object[] constructorArgs = createConstructorArgsFor(constructorArgClasses); + return enhancer.create(constructorArgClasses, constructorArgs); + } + + static Mock mockClass(final Class type, final String name) { + if (type.getDeclaringClass() != null && !Modifier.isStatic(type.getModifiers())) { + throw new IllegalArgumentException("cannot mock non-static inner class " + type.getName()); + } + + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(type); + enhancer.setClassLoader(Mock.class.getClassLoader()); + enhancer.setInterfaces(new Class[]{Mock.class, ExpectationRegistry.class}); + enhancer.setCallback(new MethodInterceptor() { + final ClassMockObject mock = new ClassMockObject(type, name); + + public Object intercept(Object thisProxy, Method method, Object[] args, MethodProxy superProxy) throws Throwable + { + try { + Class targetClass = method.getDeclaringClass(); + return (targetClass.isAssignableFrom(type)) + ? method.invoke(mock.proxy(), args) + : method.invoke(mock, args); + } + catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + }); + + Class[] constructorArgClasses = getConstructorArgClasses(type); + Object[] constructorArgs = createConstructorArgsFor(constructorArgClasses); + + return (Mock) enhancer.create(constructorArgClasses, constructorArgs); + } + + + private static Class[] getConstructorArgClasses(Class type) { + Constructor[] constructors = type.getConstructors(); + if (constructors.length == 0) { + throw new IllegalArgumentException("Cannot construct class " + type); + } + return constructors[0].getParameterTypes(); + } + + private static Object[] createConstructorArgsFor(Class[] constructorArgClasses) { + return new Object[constructorArgClasses.length]; + } + + private class ExpectationHandlerDelegate extends ExpectationHandler implements MethodInterceptor { + public Object intercept(Object thisProxy, Method method, Object[] args, MethodProxy superProxy) throws Throwable { + return this.invoke(thisProxy, method, args); + } + } +}
Added: trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/UsingClassMock.java (0 => 590)
--- trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/UsingClassMock.java (rev 0) +++ trunk/extensions/classmocks/src/java/jbehave/extensions/classmock/UsingClassMock.java 2006-11-29 15:15:11 UTC (rev 590) @@ -0,0 +1,11 @@ +package jbehave.extensions.classmock; + +import jbehave.core.minimock.UsingMiniMock; +import jbehave.core.mock.Mock; + +public class UsingClassMock extends UsingMiniMock { + + protected Mock createMock(Class type, String name) { + return ClassMockObject.mockClass(type, name); + } +}
To unsubscribe from this list please visit:
