Title: [jbehave] [590] trunk/extensions: [EK] Class mocks!
Revision
590
Author
sirenian
Date
2006-11-29 09:15:11 -0600 (Wed, 29 Nov 2006)

Log Message

[EK] Class mocks!

Modified Paths


Added Paths

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:

http://xircles.codehaus.org/manage_email

Reply via email to