From: Scott L. <sl...@sl...> - 2002-04-15 22:14:52
Attachments:
interfaceimplementor.patch
|
I couldn't get mockobjects to compile under J2SE 1.4, so I looked in the com.mockobjects.sql.* classes and found that there's a lot of code that just does "throw new UnsupportedOperationException();". J2SE 1.4 has many more methods that require this repetitive code. Instead of adding new skeletons, I removed them all and added a new class InterfaceImplementor, based on some code by Dustin Sallings. It creates these skeleton methods automatically. This InterfaceImplementor is pretty untested - I tried to be more strict about catching errors than Dustin's code, so the result is different enough to have its own bugs. I might try writing tests for it later. But it works well enough that everything compiles and the current unit tests - which sort of check its output - pass. Now the com.mockobjects.sql.* classes are more terse and work with J2SE 1.4. They will compile against extended JDBC interfaces in the future. Hopefully InterfaceImplementor can be used for other classes as well. The diffstat: build.xml | 21 src/core/com/mockobjects/util/InterfaceImplementor.java | 361 ++++++++++ src/core/com/mockobjects/util/InterfaceImplementorTask.java | 113 +++ src/jdk/common/com/mockobjects/sql/MockConnection.java | 80 -- src/jdk/common/com/mockobjects/sql/MockPreparedStatement.java | 42 - src/jdk/common/com/mockobjects/sql/MockResultSet.java | 2 src/jdk/common/com/mockobjects/sql/MockStatement.java | 99 -- 7 files changed, 499 insertions(+), 219 deletions(-) -- Scott Lamb |
From: Jeff M. <je...@mk...> - 2002-04-17 10:50:25
|
Thanks for this, but I'm not sure it's really the approach we want to be taking. I'd prefer to keep things a bit cleaner even if that means having lots of methods with just notImplemented(); in them. You might be interested in http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes your approach a bit further. There is also some work being done on use java.lang.reflect.Proxy to provide a default mock implementation. But I'm not aware of the details of this yet. On Mon, 2002-04-15 at 23:14, Scott Lamb wrote: > I couldn't get mockobjects to compile under J2SE 1.4, so I looked in the > com.mockobjects.sql.* classes and found that there's a lot of code that > just does "throw new UnsupportedOperationException();". J2SE 1.4 has > many more methods that require this repetitive code. > > Instead of adding new skeletons, I removed them all and added a new > class InterfaceImplementor, based on some code by Dustin Sallings. It > creates these skeleton methods automatically. > > This InterfaceImplementor is pretty untested - I tried to be more strict > about catching errors than Dustin's code, so the result is different > enough to have its own bugs. I might try writing tests for it later. But > it works well enough that everything compiles and the current unit tests > - which sort of check its output - pass. > > Now the com.mockobjects.sql.* classes are more terse and work with J2SE > 1.4. They will compile against extended JDBC interfaces in the future. > Hopefully InterfaceImplementor can be used for other classes as well. > > The diffstat: > > build.xml | 21 > src/core/com/mockobjects/util/InterfaceImplementor.java | 361 ++++++++++ > src/core/com/mockobjects/util/InterfaceImplementorTask.java | 113 +++ > src/jdk/common/com/mockobjects/sql/MockConnection.java | 80 -- > src/jdk/common/com/mockobjects/sql/MockPreparedStatement.java | 42 - > src/jdk/common/com/mockobjects/sql/MockResultSet.java | 2 > src/jdk/common/com/mockobjects/sql/MockStatement.java | 99 -- > 7 files changed, 499 insertions(+), 219 deletions(-) > > -- > Scott Lamb > ---- > > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/build.xml mockobjects-java.impl/build.xml > --- mockobjects-java/build.xml Mon Apr 15 16:14:01 2002 > +++ mockobjects-java.impl/build.xml Mon Apr 15 16:54:39 2002 > @@ -292,11 +292,31 @@ > description="Compile all the java files for included libraries"> > <mkdir dir="${jdk.classes}" /> > > + <taskdef name="implement" > + classname="com.mockobjects.util.InterfaceImplementorTask" > + classpath="${core.classes}"/> > + > + <implement outputPath="${out.src.dir}"> > + <class name="com.mockobjects.sql.MockConnectionStub" > + interfaces="java.sql.Connection" > + superclass="com.mockobjects.MockObject"/> > + <class name="com.mockobjects.sql.MockStatementStub" > + interfaces="java.sql.Statement" > + superclass="com.mockobjects.MockObject"/> > + <class name="com.mockobjects.sql.MockPreparedStatementStub" > + interfaces="java.sql.Statement java.sql.PreparedStatement" > + superclass="com.mockobjects.MockObject"/> > + <class name="com.mockobjects.sql.MockResultSetStub" > + interfaces="java.sql.ResultSet" > + superclass="com.mockobjects.MockObject"/> > + </implement> > + > <javac destdir="${jdk.classes}" debug="${debug}" > deprecation="${deprecation}" verbose="false" > optimize="${optimize}"> > <src path="${src.jdk.dir}/${jdk.version}" /> > <src path="${src.jdk.dir}/common" /> > + <src path="${out.src.dir}"/> > > <classpath> > <path refid="lib.classpath" /> > @@ -304,6 +324,7 @@ > <pathelement path="${core.classes}" /> > </classpath> > </javac> > + > </target> > > <target name="compile-j2ee" depends="compile-jdk" if="j2ee.version" > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/src/core/com/mockobjects/util/InterfaceImplementor.java mockobjects-java.impl/src/core/com/mockobjects/util/InterfaceImplementor.java > --- mockobjects-java/src/core/com/mockobjects/util/InterfaceImplementor.java Wed Dec 31 18:00:00 1969 > +++ mockobjects-java.impl/src/core/com/mockobjects/util/InterfaceImplementor.java Mon Apr 15 16:50:55 2002 > @@ -0,0 +1,361 @@ > +/* > + * $Id$ > + * > + * Copyright (c) 2000 Dustin Sallings <du...@sp...> > + */ > + > +package com.mockobjects.util; > + > +import java.lang.reflect.Member; > +import java.lang.reflect.Constructor; > +import java.lang.reflect.Method; > +import java.lang.reflect.Modifier; > +import java.io.File; > +import java.io.Writer; > +import java.io.OutputStreamWriter; > +import java.io.IOException; > +import java.util.ArrayList; > +import java.util.Iterator; > +import java.util.Map; > +import java.util.Set; > +import java.util.HashMap; > +import java.util.HashSet; > + > +/** > + * Creates skeleton code from interfaces. > + * <p>Mock objects contain a large number of methods which do nothing more than > + * throw UnsupportedOperationException, since mock objects only provide > + * functionality necessary for tests.</p> > + * <p>This class makes it unnecessary to manually maintain those blocks of > + * code. Instead, classes are autogenerated which contain these dummy > + * implementations. The real, manually maintained classes can inherit these or > + * vice versa.</p> > + * > + * @author Dustin Sallings <du...@sp...> > + * @version $Revision$ $Date$ > + **/ > +public class InterfaceImplementor { > + > + private String myPackageName; > + private String myClassName; > + > + /** > + * The signature of a method. > + * <p>According to the Java language specification, "The signature of a > + * method consists of the name of the method and the number and types of > + * formal parameters to the method. A class may not declare two methods > + * with the same signature, or a compile-time error occurs."</p> > + **/ > + private class Signature { > + String myName; > + Class[] myParameterTypes; > + > + /** Creates a signature to match a given method. **/ > + Signature(Method m) { > + myName = m.getName(); > + myParameterTypes = m.getParameterTypes(); > + } > + > + public boolean equals(Object oObject) { > + if (!(oObject instanceof Signature)) { > + return false; > + } > + Signature o = (Signature)oObject; > + if (!myName.equals(o.myName)) { > + return false; > + } > + if (myParameterTypes.length != o.myParameterTypes.length) { > + return false; > + } > + for (int i = 0; i < myParameterTypes.length; i ++) { > + if (!myParameterTypes[i].equals(o.myParameterTypes[i])) { > + return false; > + } > + } > + return true; > + } > + > + public int hashCode() { > + return myName.hashCode(); > + } > + } > + > + /** A set of Class objects for each implemented interface. **/ > + private Set myImplementedInterfaces = new HashSet(); > + > + /** The superclass (may or may not be present). **/ > + private Class mySuperclass; > + > + /** The constructors to inherit. **/ > + private Constructor[] myConstructors; > + > + /** A map of Signature to Method for each implemented method. **/ > + private Map myImplementedMethods = new HashMap(); > + > + /** > + * Adds an interface to the list of interfaces to be implemented. > + * @param interfaceClass The interface to implement. > + * @throws IllegalArgumentException When the class is null or > + * not an interface. > + * @throws RuntimeException If the signature conflicts with another > + * interface. > + **/ > + public void addInterface(Class aInterfaceClass) { > + if (aInterfaceClass == null) { > + throw new IllegalArgumentException( > + "aInterfaceClass must be non-null"); > + } > + > + if (!aInterfaceClass.isInterface()) { > + throw new IllegalArgumentException( > + "aInterfaceClass does not refer to an interface"); > + } > + > + if (mySuperclass != null) { > + throw new IllegalStateException( > + "no interfaces may be added after superclass is set"); > + } > + > + myImplementedInterfaces.add(aInterfaceClass); > + > + Method[] methods = aInterfaceClass.getDeclaredMethods(); > + for (int i = 0; i < methods.length; i ++) { > + Method old = (Method)myImplementedMethods.put( > + new Signature(methods[i]), > + methods[i] > + ); > + if (old != null && !areSame(old, methods[i])) { > + throw new RuntimeException("Invalid duplicated signature"); > + } > + } > + } > + > + /** > + * Sets superclass. > + * Checks for signature conflicts. Non-abstract methods in this list are > + * removed from the list to be implemented. Constructors are implemented > + * for each. > + **/ > + public void setSuperclass(Class aSuperclass) { > + if (mySuperclass != null) { > + throw new IllegalStateException( > + "The superclass may only be set once."); > + } > + mySuperclass = aSuperclass; > + myConstructors = mySuperclass.getConstructors(); > + > + // Go through methods > + Method[] methods = mySuperclass.getDeclaredMethods(); > + for (int i = 0; i < methods.length; i ++) { > + Method oldMethod = (Method)myImplementedMethods.put( > + new Signature(methods[i]), methods[i]); > + if (oldMethod != null && !areSame(oldMethod, methods[i])) { > + throw new RuntimeException("Invalid duplicated signature"); > + } > + if ((methods[i].getModifiers() & Modifier.ABSTRACT) == 0) { > + myImplementedMethods.remove(new Signature(methods[i])); > + } > + } > + } > + > + /** > + * Checks if two methods are the same. > + * This does what Method.equals() does except that it does not ensure > + * they came from the same class, and it does not check modifiers. > + **/ > + private static boolean areSame(Method a, Method b) { > + if (!a.getName().equals(b.getName())) { > + return false; > + } > + > + if (!a.getReturnType().equals(b.getReturnType())) { > + return false; > + } > + > + // Order of exceptions in getExceptionTypes() is not specified, so > + // put these into a set for comparison. > + Set aSet = new HashSet(); > + Set bSet = new HashSet(); > + Class[] aExceptions = a.getExceptionTypes(); > + for (int i = 0; i < aExceptions.length; i ++) { > + aSet.add(aExceptions[i]); > + } > + Class[] bExceptions = b.getExceptionTypes(); > + for (int i = 0; i < bExceptions.length; i ++) { > + bSet.add(bExceptions[i]); > + } > + return aSet.equals(bSet); > + } > + > + /** Gets the name of the package containing the class to generate. **/ > + public String getPackageName() { > + return myPackageName; > + } > + > + /** > + * Gets the suggested path for the package relative to a base directory. > + * @param baseDir The root of the package tree in the filesystem. > + **/ > + public File getPackageDir(File aRootDir) { > + if (myPackageName == null) { > + return aRootDir; > + } else { > + return new File(aRootDir, > + myPackageName.replace('.', File.separatorChar)); > + } > + } > + > + /** Gets the name of the class to generate. **/ > + public String getClassName() { > + return myClassName; > + } > + > + /** > + * Sets the name of the class to generate. > + * @param fullName The name of the class, with package specified if > + * the class is within a package. > + **/ > + public void setClassName(String aFullName) { > + int lastDot = aFullName.lastIndexOf("."); > + if (lastDot == -1) { > + myClassName = aFullName; > + } else { > + myPackageName = aFullName.substring(0, lastDot); > + myClassName = aFullName.substring(lastDot+1); > + } > + } > + > + /** > + * Gets the name of the type as it would appear in source code. > + * (Different from Class.toString() in the array case, especially > + * multi-dimensional arrays.) > + **/ > + private static String decodeType(Class aType) { > + String rv = null; > + if (aType.isArray()) { > + rv = decodeType(aType.getComponentType()) + "[]"; > + } else { > + rv = aType.getName(); > + } > + return rv; > + } > + > + /** > + * Implements a single method or constructor. > + * Methods will throw an UnsupportedOperationException. > + * Constructors will call superconstructors. > + * @throws IOException if unable to write to the Writer > + **/ > + private void implement(Member aMember, Writer aWriter) > + throws IOException { > + > + if (!(aMember instanceof Method || aMember instanceof Constructor)) { > + throw new IllegalArgumentException( > + "Can only implement methods and constructors"); > + } > + > + aWriter.write(" "); > + int modifiers = aMember.getModifiers(); > + modifiers &= ~Modifier.ABSTRACT; > + aWriter.write(Modifier.toString(modifiers)); > + aWriter.write(" "); > + > + Class[] parameters; > + Class[] exceptions; > + if (aMember instanceof Method) { > + aWriter.write(decodeType(((Method)aMember).getReturnType())); > + aWriter.write(" "); > + aWriter.write(aMember.getName()); > + parameters = ((Method)aMember).getParameterTypes(); > + exceptions = ((Method)aMember).getExceptionTypes(); > + } else { > + parameters = ((Constructor)aMember).getParameterTypes(); > + exceptions = ((Constructor)aMember).getExceptionTypes(); > + aWriter.write(myClassName); > + } > + aWriter.write("("); > + for (int i = 0; i < parameters.length; i ++) { > + if (i != 0) { > + aWriter.write(", "); > + } > + aWriter.write(decodeType(parameters[i]) + " a" + String.valueOf(i)); > + } > + aWriter.write(")"); > + if (exceptions.length > 0) { > + aWriter.write(" throws "); > + } > + for (int i = 0; i < exceptions.length; i ++) { > + if (i != 0) { > + aWriter.write(", "); > + } > + aWriter.write(decodeType(exceptions[i])); > + } > + aWriter.write(" {\n"); > + if (aMember instanceof Method) { > + aWriter.write("\tthrow new UnsupportedOperationException();\n"); > + } else { > + aWriter.write("\tsuper("); > + for (int i = 0; i < parameters.length; i ++) { > + if (i != 0) { > + aWriter.write(", "); > + } > + aWriter.write("a" + String.valueOf(i)); > + } > + aWriter.write(");\n"); > + } > + aWriter.write(" }\n"); > + } > + > + /** > + * Implements the entire class. > + * @throws IllegalStateException if no interfaces have been selected > + * @throws IOException if unable to write to the Writer > + **/ > + public void implement(Writer aWriter) throws IOException { > + if (myImplementedInterfaces.size() == 0) { > + throw new IllegalStateException("Implementing no interfaces!"); > + } > + > + aWriter.write( > + "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n" > + + "// Generated by com.mockobjects.util.InterfaceImplementor\n" > + + "// (version $Revision$ $Date$)\n\n"); > + > + if (myPackageName != null) { > + aWriter.write("package " + myPackageName + ";\n\n"); > + } > + > + aWriter.write("public class " + myClassName); > + if (mySuperclass != null) { > + aWriter.write(" extends " + mySuperclass.getName()); > + } > + aWriter.write(" implements "); > + Iterator it = myImplementedInterfaces.iterator(); > + int i = 0; > + while (it.hasNext()) { > + if (i ++ > 0) { > + aWriter.write(", "); > + } > + Class c = (Class)it.next(); > + aWriter.write(c.getName()); > + } > + aWriter.write(" {\n"); > + > + if (myConstructors != null) { > + for (i = 0; i < myConstructors.length; i ++) { > + aWriter.write("\n"); > + implement(myConstructors[i], aWriter); > + } > + } > + > + it = myImplementedMethods.values().iterator(); > + while (it.hasNext()) { > + aWriter.write("\n"); > + implement((Method)it.next(), aWriter); > + } > + > + aWriter.write("\n}\n"); > + aWriter.flush(); > + } > + > +} > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/src/core/com/mockobjects/util/InterfaceImplementorTask.java mockobjects-java.impl/src/core/com/mockobjects/util/InterfaceImplementorTask.java > --- mockobjects-java/src/core/com/mockobjects/util/InterfaceImplementorTask.java Wed Dec 31 18:00:00 1969 > +++ mockobjects-java.impl/src/core/com/mockobjects/util/InterfaceImplementorTask.java Mon Apr 15 16:56:36 2002 > @@ -0,0 +1,113 @@ > +/* > + * $Id$ > + * > + * Copyright (c) 2002 Scott Lamb <sl...@sl...> > + * This code is released under the MIT license; see the file LICENSE. > + */ > + > +package com.mockobjects.util; > + > +import java.io.File; > +import java.io.FileWriter; > +import java.io.IOException; > +import java.util.ArrayList; > +import java.util.StringTokenizer; > +import org.apache.tools.ant.Project; > +import org.apache.tools.ant.Task; > +import org.apache.tools.ant.BuildException; > + > +/** > + * Ant task for InterfaceImplementor. > + * > + * @author Scott Lamb <sl...@sl...> > + * @version $Revision$ $Date$ > + **/ > +public class InterfaceImplementorTask extends Task { > + > + private ArrayList myClasses = new ArrayList(); > + private String myOutputPath; > + > + public class ImplClass { > + private InterfaceImplementor myIntImpl; > + private Class mySuperclass; > + > + private ImplClass() { > + myIntImpl = new InterfaceImplementor(); > + } > + > + public void setName(String aClassName) throws BuildException { > + myIntImpl.setClassName(aClassName); > + } > + > + public void setInterfaces(String aInterfaces) throws BuildException { > + StringTokenizer interfacesList = new StringTokenizer(aInterfaces); > + while (interfacesList.hasMoreElements()) { > + String interfaceName = (String)interfacesList.nextElement(); > + try { > + Class interfaceClass = Class.forName(interfaceName); > + myIntImpl.addInterface(interfaceClass); > + } catch (ClassNotFoundException e) { > + throw new BuildException("Unable to find interface " > + + interfaceName); > + } > + } > + } > + > + public void setSuperclass(String aSuperclassName) > + throws BuildException { > + try { > + mySuperclass = Class.forName(aSuperclassName); > + } catch (ClassNotFoundException e) { > + throw new BuildException("Unable to find class " > + + aSuperclassName); > + } > + } > + > + } > + > + public void setOutputPath(String aOutputPath) throws BuildException { > + this.myOutputPath = aOutputPath; > + } > + > + public ImplClass createClass() throws BuildException { > + ImplClass s = new ImplClass(); > + myClasses.add(s); > + return s; > + } > + > + public void execute() throws BuildException { > + File destDir = new File(myOutputPath); > + for (int i = 0; i < myClasses.size(); i ++) { > + ImplClass s = (ImplClass)myClasses.get(i); > + File outFile = new File(s.myIntImpl.getPackageDir(destDir), > + s.myIntImpl.getClassName() + ".java"); > + if (outFile.exists()) { > + myClasses.remove(i--); > + } > + } > + if (myClasses.size() > 0) { > + log("Generating " + myClasses.size() + " skeleton" > + + (myClasses.size() == 1 ? "" : "s") + " to " > + + destDir.getAbsolutePath()); > + } > + for (int i = 0; i < myClasses.size(); i ++) { > + try { > + ImplClass s = (ImplClass)myClasses.get(i); > + > + File dir = s.myIntImpl.getPackageDir(destDir); > + dir.mkdirs(); > + File outFile = new File(dir, > + s.myIntImpl.getClassName() + ".java"); > + log("Generating " + outFile, Project.MSG_VERBOSE); > + FileWriter out = new FileWriter(outFile); > + if (s.mySuperclass != null) { > + s.myIntImpl.setSuperclass(s.mySuperclass); > + } > + s.myIntImpl.implement(out); > + } catch (IOException e) { > + throw new BuildException("Unable to generate skeleton", e); > + } > + } > + } > +} > + > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/src/jdk/common/com/mockobjects/sql/MockConnection.java mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockConnection.java > --- mockobjects-java/src/jdk/common/com/mockobjects/sql/MockConnection.java Sat Apr 13 10:08:23 2002 > +++ mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockConnection.java Mon Apr 15 15:46:53 2002 > @@ -4,7 +4,7 @@ > import java.util.*; > import com.mockobjects.*; > > -public class MockConnection extends MockObject implements Connection { > +public class MockConnection extends MockConnectionStub { > private ExpectationCounter myCommitCalls = new ExpectationCounter("MockConnection.commit"); > private ExpectationCounter myRollbackCalls = new ExpectationCounter("MockConnection.rollback"); > private ExpectationCounter myCloseCalls = new ExpectationCounter("MockConnection.close"); > @@ -81,38 +81,6 @@ > return myStatement; > } > > - public Statement createStatement( > - int resultSetType, > - int resultSetConcurrency) > - throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public boolean getAutoCommit() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public String getCatalog() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public DatabaseMetaData getMetaData() > - throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getTransactionIsolation() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public Map getTypeMap() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public SQLWarning getWarnings() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setupIsClosedException(SQLException aIsClosedException){ > myIsClosedException = aIsClosedException; > } > @@ -128,41 +96,12 @@ > return myIsClosed; > } > > - public boolean isReadOnly() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public String nativeSQL(String sql) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public CallableStatement prepareCall(String sql) > - throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public CallableStatement prepareCall( > - String sql, > - int resultSetType, > - int resultSetConcurrency) > - throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public PreparedStatement prepareStatement(String sql) throws SQLException { > myPreparedStatementStrings.addActual(sql); > throwStatementExceptionIfAny(); > return (PreparedStatement) myPreparedStatements.remove(0); > } > > - public PreparedStatement prepareStatement( > - String sql, > - int resultSetType, > - int resultSetConcurrency) > - throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void rollback() throws SQLException { > myRollbackCalls.inc(); > } > @@ -175,23 +114,6 @@ > myAutoCommit.setActual(autoCommit); > } > > - public void setCatalog(String catalog) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setReadOnly(boolean readOnly) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setTransactionIsolation(int level) > - throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setTypeMap(Map map) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > private void throwStatementExceptionIfAny() throws SQLException { > if (null != myStatementException) { > throw myStatementException; > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/src/jdk/common/com/mockobjects/sql/MockPreparedStatement.java mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockPreparedStatement.java > --- mockobjects-java/src/jdk/common/com/mockobjects/sql/MockPreparedStatement.java Sat Apr 13 10:08:23 2002 > +++ mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockPreparedStatement.java Mon Apr 15 15:51:39 2002 > @@ -6,7 +6,7 @@ > import java.math.BigDecimal; > import com.mockobjects.*; > > -public class MockPreparedStatement extends MockStatement implements PreparedStatement { > +public class MockPreparedStatement extends MockStatement { > private ExpectationSet mySetParameters = new ExpectationSet("MockPreparedStatement.setParameters"); > private ExpectationCounter myClearParametersCalls = new ExpectationCounter("MockPreparedStatement.clearParameters() calls"); > > @@ -73,10 +73,6 @@ > setObject(param, new Long(aLong)); > } > > - public void addBatch() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setNull(int param, int param1) throws SQLException { > setObject(param, null); > } > @@ -93,14 +89,6 @@ > setObject(param, time); > } > > - public void setObject(int param, Object obj, int targetSqlType, int scale) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setObject(int param, Object obj, int targetSqlType) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setRef(int param, Ref ref) throws SQLException { > setObject(param, ref); > } > @@ -117,26 +105,10 @@ > setObject(param, blob); > } > > - public void setCharacterStream(int param, Reader reader, int length) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setAsciiStream(int param, java.io.InputStream inputStream, int length) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setDate(int param, Date date, Calendar calendar) throws SQLException { > setDate(param, date); > } > > - public void setBinaryStream(int param, java.io.InputStream inputStream, int length) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setUnicodeStream(int param, java.io.InputStream inputStream, int length) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setBytes(int param, byte[] values) throws SQLException { > setObject(param, values); > } > @@ -153,14 +125,6 @@ > setObject(param, new Double(aDouble)); > } > > - public ResultSetMetaData getMetaData() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setTimestamp(int param, Timestamp timestamp, Calendar calendar) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setTime(int param, Time time) throws SQLException { > setObject(param, time); > } > @@ -169,10 +133,6 @@ > setObject(param, new Boolean(aBoolean)); > } > > - public void setNull(int param, int param1, String typeName) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public void setBigDecimal(int param, BigDecimal bigDecimal) throws SQLException { > setObject(param, bigDecimal); > } > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/src/jdk/common/com/mockobjects/sql/MockResultSet.java mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockResultSet.java > --- mockobjects-java/src/jdk/common/com/mockobjects/sql/MockResultSet.java Sat Apr 13 10:08:23 2002 > +++ mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockResultSet.java Mon Apr 15 15:47:47 2002 > @@ -20,7 +20,7 @@ > * It also counts close() and next() calls > * To force throwing a SQLException on a getter, set the corresponding value to be of type SQLException. > */ > -abstract public class MockResultSet extends MockObject implements ResultSet { > +abstract public class MockResultSet extends MockResultSetStub { > private ExpectationCounter myCloseCalls = new ExpectationCounter("MockResultSet.close"); > protected ExpectationCounter myNextCalls = new ExpectationCounter("MockResultSet.next"); > > diff -Nru --exclude CVS --exclude ant.jar mockobjects-java/src/jdk/common/com/mockobjects/sql/MockStatement.java mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockStatement.java > --- mockobjects-java/src/jdk/common/com/mockobjects/sql/MockStatement.java Sat Apr 13 10:08:23 2002 > +++ mockobjects-java.impl/src/jdk/common/com/mockobjects/sql/MockStatement.java Mon Apr 15 15:44:05 2002 > @@ -4,7 +4,7 @@ > import junit.framework.*; > import com.mockobjects.*; > > -public class MockStatement extends MockObject implements Statement { > +public class MockStatement extends MockStatementStub { > protected ExpectationCounter myCloseCalls = new ExpectationCounter("MockStatement.closeCalls"); > protected ExpectationCounter myExecuteCalls = new ExpectationCounter("MockStatement.executeCalls"); > protected ExpectationValue myQueryString = new ExpectationValue("MockStatement.queryString"); > @@ -52,10 +52,6 @@ > myCloseCalls.inc(); > } > > - public boolean execute(String sql) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public ResultSet executeQuery(String sql) throws SQLException { > myQueryString.setActual(sql); > innerExecute(); > @@ -68,100 +64,7 @@ > return myUpdateCount; > } > > - public int getMaxFieldSize() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setMaxFieldSize(int max) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getMaxRows() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setMaxRows(int max) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setEscapeProcessing(boolean enable) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getQueryTimeout() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setQueryTimeout(int seconds) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void cancel() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public SQLWarning getWarnings() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void clearWarnings() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setCursorName(String name) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public ResultSet getResultSet() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > public int getUpdateCount() throws SQLException { > return myUpdateCount; > } > - > - public boolean getMoreResults() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setFetchDirection(int direction) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getFetchDirection() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void setFetchSize(int rows) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getFetchSize() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getResultSetConcurrency() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int getResultSetType() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void addBatch(String sql) throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public void clearBatch() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public int[] executeBatch() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > - public Connection getConnection() throws SQLException { > - throw new UnsupportedOperationException(); > - } > - > } -- |
From: Scott L. <sl...@sl...> - 2002-04-17 12:25:17
|
On Wed, Apr 17, 2002 at 11:46:28AM +0100, Jeff Martin wrote: > Thanks for this, but I'm not sure it's really the approach we want to be > taking. I'd prefer to keep things a bit cleaner even if that means > having lots of methods with just notImplemented(); in them. I have to disagree - I don't think that's the clean approach. I don't like the idea of humans creating anything repetitive, anything that a computer could create. There's more possibility for error that way. Or even copying/pasting repetitive, automatically generated code. That code just serves to obscure where the real work is being done. > You might be interested in > http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes your > approach a bit further. > > There is also some work being done on use java.lang.reflect.Proxy to > provide a default mock implementation. But I'm not aware of the details > of this yet. Those are both interesting. I'll look more at them. Thanks. -- Scott Lamb |
From: Jeff M. <je...@mk...> - 2002-04-17 12:57:23
|
My problem is with the autogeneration, but with what is being generated. I'm not happy with having the stub classes which are gradually superseded, I think it could leave us with lots of classes which eventually serve no useful purpose. As a starting point for new mocks I don't have a problem with generating the code, but creating stubs for everything is not something I'm happy with. But of course that's just my opinion, others may feel differently ;o) On Wed, 2002-04-17 at 13:25, Scott Lamb wrote: > On Wed, Apr 17, 2002 at 11:46:28AM +0100, Jeff Martin wrote: > > Thanks for this, but I'm not sure it's really the approach we want to be > > taking. I'd prefer to keep things a bit cleaner even if that means > > having lots of methods with just notImplemented(); in them. > > I have to disagree - I don't think that's the clean approach. I don't like the > idea of humans creating anything repetitive, anything that a computer could > create. There's more possibility for error that way. Or even copying/pasting > repetitive, automatically generated code. That code just serves to obscure > where the real work is being done. > > > You might be interested in > > http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes your > > approach a bit further. > > > > There is also some work being done on use java.lang.reflect.Proxy to > > provide a default mock implementation. But I'm not aware of the details > > of this yet. > > Those are both interesting. I'll look more at them. > > Thanks. > > -- > Scott Lamb > > _______________________________________________ > Mockobjects-java-dev mailing list > Moc...@li... > https://lists.sourceforge.net/lists/listinfo/mockobjects-java-dev -- |
From: Steve F. <st...@m3...> - 2002-04-17 21:27:26
|
For those of us (unlike Jeff) using an IDE, aligning class with interfaces is pretty easy. What I find more interesting is the idea of using dynamic proxies to catch the unimplemented methods (like Smalltalk doesNotUnderstand), rather than the EasyMock approach of using a dynamic proxy to record and playback the behaviour. You could then use local overrides to implement the behaviour for a given test. Now Jeff has split the jdk's it might be worth investigating this for versions 1.3+ Steve ----- Original Message ----- From: "Jeff Martin" <je...@mk...> To: "MockObjects" <moc...@li...> Sent: Wednesday, April 17, 2002 1:53 PM Subject: Re: [MO-java-dev] InterfaceImplementor > My problem is with the autogeneration, but with what is being generated. > I'm not happy with having the stub classes which are gradually > superseded, I think it could leave us with lots of classes which > eventually serve no useful purpose. > > As a starting point for new mocks I don't have a problem with generating > the code, but creating stubs for everything is not something I'm happy > with. > > But of course that's just my opinion, others may feel differently ;o) > > On Wed, 2002-04-17 at 13:25, Scott Lamb wrote: > > On Wed, Apr 17, 2002 at 11:46:28AM +0100, Jeff Martin wrote: > > > Thanks for this, but I'm not sure it's really the approach we want to be > > > taking. I'd prefer to keep things a bit cleaner even if that means > > > having lots of methods with just notImplemented(); in them. > > > > I have to disagree - I don't think that's the clean approach. I don't like the > > idea of humans creating anything repetitive, anything that a computer could > > create. There's more possibility for error that way. Or even copying/pasting > > repetitive, automatically generated code. That code just serves to obscure > > where the real work is being done. > > > > > You might be interested in > > > http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes your > > > approach a bit further. > > > > > > There is also some work being done on use java.lang.reflect.Proxy to > > > provide a default mock implementation. But I'm not aware of the details > > > of this yet. > > > > Those are both interesting. I'll look more at them. |
From: Jeff M. <je...@mk...> - 2002-04-18 09:31:29
|
I find !!javap path.to.Interface works fairly, and I bet if I wasn't so lazy I could write a vim macro to do the rest. Someones implemented tetris in vim so I should be able do do that. Try that in IDEA ;-P !!javap path.to.Interface :1,$s/abstract // :1,$s/;/{^M^I^InotImplemented();^M} That would probably do it. On Wed, 2002-04-17 at 22:21, Steve Freeman wrote: > For those of us (unlike Jeff) using an IDE, aligning class with > interfaces is pretty easy. > > What I find more interesting is the idea of using dynamic proxies to > catch the unimplemented methods (like Smalltalk doesNotUnderstand), > rather than the EasyMock approach of using a dynamic proxy to record and > playback the behaviour. You could then use local overrides to implement > the behaviour for a given test. Now Jeff has split the jdk's it might be > worth investigating this for versions 1.3+ > > Steve > > ----- Original Message ----- > From: "Jeff Martin" <je...@mk...> > To: "MockObjects" <moc...@li...> > Sent: Wednesday, April 17, 2002 1:53 PM > Subject: Re: [MO-java-dev] InterfaceImplementor > > > > My problem is with the autogeneration, but with what is being > generated. > > I'm not happy with having the stub classes which are gradually > > superseded, I think it could leave us with lots of classes which > > eventually serve no useful purpose. > > > > As a starting point for new mocks I don't have a problem with > generating > > the code, but creating stubs for everything is not something I'm happy > > with. > > > > But of course that's just my opinion, others may feel differently ;o) > > > > On Wed, 2002-04-17 at 13:25, Scott Lamb wrote: > > > On Wed, Apr 17, 2002 at 11:46:28AM +0100, Jeff Martin wrote: > > > > Thanks for this, but I'm not sure it's really the approach we want > to be > > > > taking. I'd prefer to keep things a bit cleaner even if that means > > > > having lots of methods with just notImplemented(); in them. > > > > > > I have to disagree - I don't think that's the clean approach. I > don't like the > > > idea of humans creating anything repetitive, anything that a > computer could > > > create. There's more possibility for error that way. Or even > copying/pasting > > > repetitive, automatically generated code. That code just serves to > obscure > > > where the real work is being done. > > > > > > > You might be interested in > > > > http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes > your > > > > approach a bit further. > > > > > > > > There is also some work being done on use java.lang.reflect.Proxy > to > > > > provide a default mock implementation. But I'm not aware of the > details > > > > of this yet. > > > > > > Those are both interesting. I'll look more at them. > > > > > _______________________________________________ > Mockobjects-java-dev mailing list > Moc...@li... > https://lists.sourceforge.net/lists/listinfo/mockobjects-java-dev -- |
From: Jeff M. <je...@mk...> - 2002-04-18 11:27:34
Attachments:
mock.vim
|
Here you go. Just drop it into ~/.vim/plugin, start up vim, type :call MockIt("this.is.the.Interface") Easy as that. Still need to sort out a proper name mapping so you can do :mockit this.is.the.Interface and it doesn't put in variable names for the method arguments, but I'll get there. On Wed, 2002-04-17 at 22:21, Steve Freeman wrote: > For those of us (unlike Jeff) using an IDE, aligning class with > interfaces is pretty easy. > > What I find more interesting is the idea of using dynamic proxies to > catch the unimplemented methods (like Smalltalk doesNotUnderstand), > rather than the EasyMock approach of using a dynamic proxy to record and > playback the behaviour. You could then use local overrides to implement > the behaviour for a given test. Now Jeff has split the jdk's it might be > worth investigating this for versions 1.3+ > > Steve > > ----- Original Message ----- > From: "Jeff Martin" <je...@mk...> > To: "MockObjects" <moc...@li...> > Sent: Wednesday, April 17, 2002 1:53 PM > Subject: Re: [MO-java-dev] InterfaceImplementor > > > > My problem is with the autogeneration, but with what is being > generated. > > I'm not happy with having the stub classes which are gradually > > superseded, I think it could leave us with lots of classes which > > eventually serve no useful purpose. > > > > As a starting point for new mocks I don't have a problem with > generating > > the code, but creating stubs for everything is not something I'm happy > > with. > > > > But of course that's just my opinion, others may feel differently ;o) > > > > On Wed, 2002-04-17 at 13:25, Scott Lamb wrote: > > > On Wed, Apr 17, 2002 at 11:46:28AM +0100, Jeff Martin wrote: > > > > Thanks for this, but I'm not sure it's really the approach we want > to be > > > > taking. I'd prefer to keep things a bit cleaner even if that means > > > > having lots of methods with just notImplemented(); in them. > > > > > > I have to disagree - I don't think that's the clean approach. I > don't like the > > > idea of humans creating anything repetitive, anything that a > computer could > > > create. There's more possibility for error that way. Or even > copying/pasting > > > repetitive, automatically generated code. That code just serves to > obscure > > > where the real work is being done. > > > > > > > You might be interested in > > > > http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes > your > > > > approach a bit further. > > > > > > > > There is also some work being done on use java.lang.reflect.Proxy > to > > > > provide a default mock implementation. But I'm not aware of the > details > > > > of this yet. > > > > > > Those are both interesting. I'll look more at them. > > > > > _______________________________________________ > Mockobjects-java-dev mailing list > Moc...@li... > https://lists.sourceforge.net/lists/listinfo/mockobjects-java-dev -- |
From: Tim M. <tim...@po...> - 2002-04-18 22:12:37
|
Guys - Am quite taken by the fact that people are using this stuff now - so the discussions are interesting the contributions well received. With regards to dynamic proxies - the idea is good, however I can't escape the fact that having mock objects complain when you change things (e.g. they break) has actually saved my bacon a number of times when refactoring or making changes. It really drives home what will be affected. This could of course be a different way of working so I am personally still considering how it would change the way I code. At the moment I like the clean breaks (eg. obvious compile errors). Tim -----Original Message----- From: moc...@li... [mailto:moc...@li...]On Behalf Of Steve Freeman Sent: 17 April 2002 22:22 To: MockObjects Subject: Re: [MO-java-dev] InterfaceImplementor For those of us (unlike Jeff) using an IDE, aligning class with interfaces is pretty easy. What I find more interesting is the idea of using dynamic proxies to catch the unimplemented methods (like Smalltalk doesNotUnderstand), rather than the EasyMock approach of using a dynamic proxy to record and playback the behaviour. You could then use local overrides to implement the behaviour for a given test. Now Jeff has split the jdk's it might be worth investigating this for versions 1.3+ Steve ----- Original Message ----- From: "Jeff Martin" <je...@mk...> To: "MockObjects" <moc...@li...> Sent: Wednesday, April 17, 2002 1:53 PM Subject: Re: [MO-java-dev] InterfaceImplementor > My problem is with the autogeneration, but with what is being generated. > I'm not happy with having the stub classes which are gradually > superseded, I think it could leave us with lots of classes which > eventually serve no useful purpose. > > As a starting point for new mocks I don't have a problem with generating > the code, but creating stubs for everything is not something I'm happy > with. > > But of course that's just my opinion, others may feel differently ;o) > > On Wed, 2002-04-17 at 13:25, Scott Lamb wrote: > > On Wed, Apr 17, 2002 at 11:46:28AM +0100, Jeff Martin wrote: > > > Thanks for this, but I'm not sure it's really the approach we want to be > > > taking. I'd prefer to keep things a bit cleaner even if that means > > > having lots of methods with just notImplemented(); in them. > > > > I have to disagree - I don't think that's the clean approach. I don't like the > > idea of humans creating anything repetitive, anything that a computer could > > create. There's more possibility for error that way. Or even copying/pasting > > repetitive, automatically generated code. That code just serves to obscure > > where the real work is being done. > > > > > You might be interested in > > > http://www.xpdeveloper.com/cgi-bin/wiki.cgi?MockMaker which takes your > > > approach a bit further. > > > > > > There is also some work being done on use java.lang.reflect.Proxy to > > > provide a default mock implementation. But I'm not aware of the details > > > of this yet. > > > > Those are both interesting. I'll look more at them. _______________________________________________ Mockobjects-java-dev mailing list Moc...@li... https://lists.sourceforge.net/lists/listinfo/mockobjects-java-dev --- Incoming mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.349 / Virus Database: 195 - Release Date: 15/04/2002 --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.349 / Virus Database: 195 - Release Date: 15/04/2002 |
From: Scott L. <sl...@sl...> - 2002-04-18 18:40:35
|
On Thu, Apr 18, 2002 at 12:23:57PM +0100, Jeff Martin wrote: > Here you go. Just drop it into ~/.vim/plugin, start up vim, type :call > MockIt("this.is.the.Interface") > > Easy as that. > > Still need to sort out a proper name mapping so you can do > > :mockit this.is.the.Interface > > and it doesn't put in variable names for the method arguments, but I'll > get there. I still say this isn't as good. Even though you don't have to manually type out the interface the first time, - if the interface changes (as in the SQL example), you need to manually sort it out. With the stubs, you don't. - it's more work to catch errors. My stub generator will immediately complain if there are conflicting methods with the same signature. (Or should. It needs more testing.) - the source code is cluttered up with lots of methods that aren't implemented, obscuring what actually does work. -- Scott Lamb |
From: Jeff M. <je...@mk...> - 2002-04-19 08:54:06
|
On Thu, 2002-04-18 at 19:40, Scott Lamb wrote: > On Thu, Apr 18, 2002 at 12:23:57PM +0100, Jeff Martin wrote: > > Here you go. Just drop it into ~/.vim/plugin, start up vim, type :call > > MockIt("this.is.the.Interface") > > > > Easy as that. > > > > Still need to sort out a proper name mapping so you can do > > > > :mockit this.is.the.Interface > > > > and it doesn't put in variable names for the method arguments, but I'll > > get there. > > I still say this isn't as good. Even though you don't have to manually type > out the interface the first time, It was a half joke really, people are trying to persuade me that I should use an ide, coz it save you time doing a couple of things. I like vim, it saves me hassle nearly ever single keystroke > > - if the interface changes (as in the SQL example), you need to manually > sort it out. With the stubs, you don't. Doesn't this then mean that we revert to the stub implementation, which will thrown an exception only when it's called. Not at compilation. Well only know about the problem when someone tries to use the mock not when the interface was changed. I'd prefer not to have the class compile than to silently change it's behavior. We end up loosing the advantage of having a compiled language. This is a similar point to tim's. > - it's more work to catch errors. My stub generator will immediately > complain if there are conflicting methods with the same signature. (Or > should. It needs more testing.) > - the source code is cluttered up with lots of methods that aren't > implemented, obscuring what actually does work. I'm in two minds about this point, cluttered code bad, on the other hand. You can just look at stack-trace telling you which line is not implemented, go to the line and add the code. Works quite well I find. > > -- > Scott Lamb > Keep going you might yet persuade me ;o) |