You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/07/14 17:06:30 UTC

git commit: ISIS-463: can now intermix @unit and @integration level specs.

Updated Branches:
  refs/heads/master 9a9f55e6e -> 3d271d24c


ISIS-463: can now intermix @unit and @integration level specs.

* renamed ScenarioExecution's get and put to getVar and putVar
* added a removeVar
* updated corresponding convenience methods in IntegationTestAbstract and CukeStepDefsAbstract
* added supportsMocks into CukeStepDefsAbstract
* refactored todo specs with guards (necessary, unfortunately)
- InMemoryDB utility class refactorings
- fixed license header comments.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/3d271d24
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/3d271d24
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/3d271d24

Branch: refs/heads/master
Commit: 3d271d24ca5fedbdbf796fd069a061920ba2e7fa
Parents: 9a9f55e
Author: Dan Haywood <da...@apache.org>
Authored: Sun Jul 14 16:06:14 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Sun Jul 14 16:06:14 2013 +0100

----------------------------------------------------------------------
 .../IntegrationTestAbstract.java                |  21 ++-
 .../ScenarioExecutionForIntegration.java        |  12 +-
 .../core/specsupport/scenarios/InMemoryDB.java  |  94 +++++++---
 .../scenarios/ScenarioExecution.java            | 100 ++++++++---
 .../scenarios/ScenarioExecutionForUnit.java     |   4 +
 .../specsupport/specs/CukeStepDefsAbstract.java |  31 +++-
 .../java/fixture/todo/ToDoItemsFixture.java     |   4 +-
 .../integtests/pom.xml                          |   1 +
 .../java/integration/ToDoSystemInitializer.java |  26 +--
 .../todoitem/BootstrapIntegrationStepDefs.java  |  26 +--
 .../FindAndCompleteToDoItemsSpec.feature        |  38 ++++
 .../todoitem/FindAndCompleteToDoItemsSpec.java  |  37 ++++
 ...dToDoItemAndMarkAsNotYetCompleteSpec.feature |  34 ++++
 ...etedToDoItemAndMarkAsNotYetCompleteSpec.java |  37 ++++
 .../specs/todoitem/ToDoItemSpecs.feature        |  13 --
 .../specs/todoitem/ToDoItemSpecs.java           |  37 ----
 .../specs/todoitem/ToDoItemStepDefs.java        | 175 ++++++++++++-------
 17 files changed, 486 insertions(+), 204 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract.java
index 938dd17..50f5ede 100644
--- a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract.java
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract.java
@@ -52,22 +52,29 @@ public abstract class IntegrationTestAbstract {
     /**
      * Convenience method
      */
-    public void put(String type, String id, Object value) {
-        scenarioExecution().put(type, id, value);
+    public Object getVar(String type, String id) {
+        return scenarioExecution().getVar(type, id);
     }
-    
+
     /**
      * Convenience method
      */
-    public Object get(String type, String id) {
-        return scenarioExecution().get(type, id);
+    public <X> X getVar(String type, String id, Class<X> cls) {
+        return scenarioExecution().getVar(type, id ,cls);
     }
 
     /**
      * Convenience method
      */
-    public <X> X get(String type, String id, Class<X> cls) {
-        return scenarioExecution().get(type, id ,cls);
+    public void putVar(String type, String id, Object value) {
+        scenarioExecution().putVar(type, id, value);
+    }
+    
+    /**
+     * Convenience method
+     */
+    public void removeVar(String type, String id) {
+        scenarioExecution().removeVar(type, id);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionForIntegration.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionForIntegration.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionForIntegration.java
index 6e822ac..4330e5a 100644
--- a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionForIntegration.java
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/scenarios/ScenarioExecutionForIntegration.java
@@ -16,6 +16,17 @@
  */
 package org.apache.isis.core.integtestsupport.scenarios;
 
+import org.hamcrest.Description;
+import org.hamcrest.StringDescription;
+import org.jmock.Sequence;
+import org.jmock.States;
+import org.jmock.internal.ExpectationBuilder;
+import org.jmock.internal.InvocationExpectation;
+import org.jmock.internal.NamedSequence;
+import org.jmock.internal.State;
+import org.jmock.internal.StateMachine;
+import org.jmock.internal.StatePredicate;
+
 import org.apache.isis.applib.fixtures.InstallableFixture;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.core.integtestsupport.IsisSystemForTest;
@@ -79,5 +90,4 @@ public class ScenarioExecutionForIntegration extends ScenarioExecution  {
         }
     }
 
-
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/InMemoryDB.java
----------------------------------------------------------------------
diff --git a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/InMemoryDB.java b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/InMemoryDB.java
index 6c8d266..2ffb7c2 100644
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/InMemoryDB.java
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/InMemoryDB.java
@@ -16,8 +16,12 @@
  */
 package org.apache.isis.core.specsupport.scenarios;
 
+import java.util.List;
 import java.util.Map;
 
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 import org.hamcrest.Description;
@@ -27,10 +31,10 @@ import org.jmock.api.Invocation;
 import org.apache.isis.applib.DomainObjectContainer;
 
 /**
- * To support unit-scope specifications, intended to work with mocks.
+ * Utility class to support the writing of unit-scope specs.
  * 
  * <p>
- * The {@link #findByXxx(Class, Strategy)} provides an implementation of a JMock
+ * The {@link #finds(Class, Strategy)} provides an implementation of a JMock
  * {@link Action} that can simulate searching for an object from a database, and 
  * optionally automatically creating a new one if {@link Strategy specified}.
  * 
@@ -52,12 +56,15 @@ public class InMemoryDB {
     }
     
     public static class EntityId {
-        private final String type;
+        private final Class<?> type;
         private final String id;
         public EntityId(Class<?> type, String id) {
-            this.type = type.getName();
+            this.type = type;
             this.id = id;
         }
+        Class<?> getType() {
+            return type;
+        }
         @Override
         public int hashCode() {
             final int prime = 31;
@@ -95,8 +102,11 @@ public class InMemoryDB {
     
     private Map<InMemoryDB.EntityId, Object> objectsById = Maps.newHashMap();
     
+    /**
+     * Returns the object if exists, but will NOT instantiate a new one if not present.
+     */
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    public <T> T get(final Class<T> cls, final String id) {
+    public <T> T getNoCreate(final Class<T> cls, final String id) {
         Class type = cls;
         while(type != null) {
             // search for this class and all superclasses
@@ -110,15 +120,30 @@ public class InMemoryDB {
         return null;
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
+    /**
+     * Returns the object if exists, else will instantiate and save a new one if not present.
+     * 
+     * <p>
+     * The new object will have services injected into it (through the {@link ScenarioExecution#injectServices(Object)})
+     * and will be initialized through the {@link #init(Object, String) init hook} method.
+     */
+    @SuppressWarnings({ "unchecked" })
     public <T> T getElseCreate(final Class<T> cls, final String id) {
-        final Object object = get(cls, id);
+        final Object object = getNoCreate(cls, id);
         if(object != null) { 
             return (T) object;
         }
         Object obj = instantiateAndInject(cls);
         init(obj, id);
         
+        return put(cls, id, obj);
+    }
+
+    /**
+     * Put an object into the database.
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public <T> T put(final Class<T> cls, final String id, Object obj) {
         Class type = cls;
         // put for this class and all superclasses
         while(type != null) {
@@ -137,12 +162,19 @@ public class InMemoryDB {
         }
     }
 
-    public enum Strategy {
-        STRICT,
-        AUTOCREATE
-    }
-    
-    public Action findByXxx(final Class<?> cls, final InMemoryDB.Strategy strategy) {
+    /**
+     * Returns a JMock {@link Action} to return an instance of the provided class.
+     * 
+     * <p>
+     * If the object is not yet held in memory, it will be automatically created,
+     * as per {@link #getElseCreate(Class, String)}.
+     * 
+     * <p>
+     * This {@link Action} can only be set for expectations to invoke a method
+     * accepting a single string argument.  This string argument is taken to be an
+     * identifier for the object (and is used in the caching of that object in memory).  
+     */
+    public Action finds(final Class<?> cls) {
         return new Action() {
             
             @Override
@@ -155,23 +187,43 @@ public class InMemoryDB {
                     throw new IllegalArgumentException("Argument must be a string");
                 } 
                 String arg = (String) argObj;
-                if(strategy == Strategy.AUTOCREATE) {
-                    return getElseCreate(cls, arg);
-                } else {
-                    return get(cls, arg);
-                }
+                return getElseCreate(cls, arg);
             }
             
             @Override
             public void describeTo(Description description) {
-                description.appendText("findByXxx for " + cls.getName());
+                description.appendText("finds an instance of " + cls.getName());
             }
         };
     }
-    
+
+    public <T> List<T> findAll(Class<T> cls) {
+        return find(cls, Predicates.<T>alwaysTrue());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> List<T> find(Class<T> cls, Predicate<T> predicate) {
+        final List<T> list = Lists.newArrayList(); 
+        for (EntityId entityId : objectsById.keySet()) {
+            if(cls.isAssignableFrom(entityId.getType())) {
+                final T object = (T) objectsById.get(entityId);
+                if(predicate.apply(object)) {
+                    list.add(object);
+                }
+            }
+        }
+        return list;
+    }
+
     /**
      * Hook to initialize if possible.
+     * 
+     * <p>
+     * The provided string is usually taken to be some sort of unique identifier for the object
+     * (unique in the context of any given scenario, that is).
      */
-    protected void init(Object obj, String id) {
+    protected void init(Object obj, String str) {
     }
+
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecution.java
----------------------------------------------------------------------
diff --git a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecution.java b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecution.java
index 61cd893..59864e4 100644
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecution.java
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecution.java
@@ -21,6 +21,7 @@ import java.util.Map;
 
 import com.google.common.collect.Maps;
 
+import org.jmock.Mockery;
 import org.jmock.Sequence;
 import org.jmock.States;
 import org.jmock.internal.ExpectationBuilder;
@@ -28,7 +29,6 @@ import org.jmock.internal.ExpectationBuilder;
 import org.apache.isis.applib.DomainObjectContainer;
 import org.apache.isis.applib.fixtures.InstallableFixture;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.core.wrapper.WrapperFactoryDefault;
 
 
 /**
@@ -116,8 +116,7 @@ public abstract class ScenarioExecution {
      * otherwise returns a {@link WrapperFactory#NOOP no-op} implementation.
      */
     public WrapperFactory wrapperFactory() {
-        final WrapperFactory wrapperFactory = dsp.getService(WrapperFactory.class);
-        return wrapperFactory != null? wrapperFactory: WrapperFactory.NOOP;
+        return WrapperFactory.NOOP;
     }
 
 
@@ -206,21 +205,41 @@ public abstract class ScenarioExecution {
     
     private final Map<String, Object> mostRecent = Maps.newHashMap();
 
-    public void put(String type, String id, Object value) {
-        objectByVariableId.put(new VariableId(type, id), value);
+    public void putVar(String type, String id, Object value) {
+        if(type == null || id == null) {
+            throw new IllegalArgumentException("type and id must both be provided to save a scenario variable");
+        }
+        if(value == null) {
+            throw new IllegalArgumentException("value cannot be null; use remove() to clear an scenario variable");
+        }
+        final VariableId key = new VariableId(type, id);
+        objectByVariableId.put(key, value);
         objectsById.put(id, value);
         mostRecent.put(type, value);
     }
 
+    public void removeVar(String type, String id) {
+        if(type != null && id != null) {
+            final VariableId key = new VariableId(type, id);
+            objectByVariableId.remove(key);
+        }
+        if(id != null) {
+            objectsById.remove(id);
+        }
+        if(type != null) {
+            mostRecent.remove(type);
+        }
+    }
+
     /**
-     * Retrieve an object previously used in the scenario.
+     * Retrieve an variable previously used in the scenario.
      * 
      * <p>
      * Must specify type and/or id.
      * 
      * @see VariableId - for rules on what constitutes an identifier.
      */
-    public Object get(String type, String id) {
+    public Object getVar(String type, String id) {
         if(type != null && id != null) {
             final VariableId variableId = new VariableId(type,id);
             final Object value = objectByVariableId.get(variableId);
@@ -244,59 +263,83 @@ public abstract class ScenarioExecution {
     }
 
     /**
-     * As {@link #get(String, String)}, but downcasting to the provided class.
+     * As {@link #getVar(String, String)}, but downcasting to the provided class.
      */
     @SuppressWarnings("unchecked")
-    public <X> X get(String type, String id, Class<X> cls) {
-        return (X) get(type, id);
+    public <X> X getVar(String type, String id, Class<X> cls) {
+        return (X) getVar(type, id);
     }
 
     // //////////////////////////////////////
 
     /**
-     * Install expectations on mock domain services.
+     * Whether this implementation supports mocks.
      * 
      * <p>
-     * This implementation is a no-op, but subclasses of this class tailored to
-     * supporting unit specs/tests are expected to override.
+     * This default implementation returns <tt>false</tt>, meaning that the methods to
+     * support mocking ({@link #checking(ExpectationBuilder)}, {@link #assertIsSatisfied()}, 
+     * {@link #sequence(String)} and {@link #states(String)}) may not be called.  However, 
+     * the {@link ScenarioExecutionForUnit} overrides this and does support mocking.
+     */
+    public boolean supportsMocks() {
+        return false;
+    }
+
+    /**
+     * Install expectations on mock domain services (if appropriate).
+     *
+     * <p>
+     * By default, mocks are not supported.  However, {@link ScenarioExecutionForUnit} overrides this
+     * method and does support mocking (delegating to an underlying JMock {@link Mockery}).
+     * 
+     * <p>
+     * Subclasses of this class tailored to supporting integration specs/tests should do nothing
      */
     public void checking(ExpectationBuilder expectations) {
-        // do nothing
+        throw new IllegalStateException("Mocks are not supported");
     }
     
     /**
-     * Install expectations on mock domain services.
+     * Install expectations on mock domain services (if appropriate).
+     *
+     * <p>
+     * By default, mocks are not supported.  To reduce clutter in tests, this method is a no-op
+     * and will silently do nothing if called when mocks are not supported.
      * 
      * <p>
-     * This implementation is a no-op, but subclasses of this class tailored to
-     * supporting unit specs/tests are expected to override.
+     * The {@link ScenarioExecutionForUnit} overrides this method and does support mocking, delegating 
+     * to an underlying JMock {@link Mockery}).  Not only will it assert all existing interactions
+     * have been satisfied, it also resets mocks/expectations for the next interaction. 
      */
     public void assertIsSatisfied() {
-        // do nothing
     }
     
     /**
-     * Define {@link Sequence} in a (JMock) interaction.
+     * Define {@link Sequence} in a (JMock) interaction  (if appropriaate).
+     *
+     * <p>
+     * By default, mocks are not supported.  However, {@link ScenarioExecutionForUnit} overrides this
+     * method and does support mocking (delegating to an underlying JMock {@link Mockery}).
      * 
      * <p>
-     * This implementation is a no-op, but subclasses of this class tailored to
-     * supporting unit specs/tests are expected to override.
+     * Subclasses of this class tailored to supporting integration specs/tests should do nothing
      */
     public Sequence sequence(String name) {
-        // do nothing
-        return null;
+        throw new IllegalStateException("Mocks are not supported");
     }
     
     /**
-     * Define {@link States} in a (JMock) interaction.
+     * Define {@link States} in a (JMock) interaction (if appropriaate).
+     *
+     * <p>
+     * By default, mocks are not supported.  However, {@link ScenarioExecutionForUnit} overrides this
+     * method and does support mocking (delegating to an underlying JMock {@link Mockery}).
      * 
      * <p>
-     * This implementation is a no-op, but subclasses of this class tailored to
-     * supporting unit specs/tests are expected to override.
+     * Subclasses of this class tailored to supporting integration specs/tests should do nothing
      */
     public States states(String name) {
-        // do nothing
-        return null;
+        throw new IllegalStateException("Mocks are not supported");
     }
     
     // //////////////////////////////////////
@@ -365,4 +408,5 @@ public abstract class ScenarioExecution {
         }
     }
 
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecutionForUnit.java
----------------------------------------------------------------------
diff --git a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecutionForUnit.java b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecutionForUnit.java
index d29b3ce..b1768b3 100644
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecutionForUnit.java
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/scenarios/ScenarioExecutionForUnit.java
@@ -48,6 +48,10 @@ public class ScenarioExecutionForUnit extends ScenarioExecution {
 
     // //////////////////////////////////////
 
+    @Override
+    public boolean supportsMocks() {
+        return true;
+    }
     /**
      * Sets up an expectation against the underlying JMock {@link Mockery} 
      * (as wrapped by {@link DomainServiceProviderMockery}).

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeStepDefsAbstract.java
----------------------------------------------------------------------
diff --git a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeStepDefsAbstract.java b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeStepDefsAbstract.java
index f87574a..f552d45 100644
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeStepDefsAbstract.java
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeStepDefsAbstract.java
@@ -68,24 +68,31 @@ public abstract class CukeStepDefsAbstract {
     /**
      * Convenience method
      */
-    public void put(String type, String id, Object value) {
-        scenarioExecution().put(type, id, value);
+    public Object getVar(String type, String id) {
+        return scenarioExecution().getVar(type, id);
     }
     
     /**
      * Convenience method
      */
-    public Object get(String type, String id) {
-        return scenarioExecution().get(type, id);
+    public <X> X getVar(String type, String id, Class<X> cls) {
+        return scenarioExecution().getVar(type, id ,cls);
     }
     
     /**
      * Convenience method
      */
-    public <X> X get(String type, String id, Class<X> cls) {
-        return scenarioExecution().get(type, id ,cls);
+    public void putVar(String type, String id, Object value) {
+        scenarioExecution().putVar(type, id, value);
     }
-    
+
+    /**
+     * Convenience method
+     */
+    public void removeVar(String type, String id) {
+        scenarioExecution().removeVar(type, id);
+    }
+
     /**
      * Convenience method
      */
@@ -123,6 +130,14 @@ public abstract class CukeStepDefsAbstract {
     
     /**
      * Convenience method
+     * @return 
+     */
+    public boolean supportsMocks() {
+        return scenarioExecution().supportsMocks();
+    }
+    
+    /**
+     * Convenience method
      */
     public void checking(ExpectationBuilder expectations) {
         scenarioExecution().checking(expectations);
@@ -131,7 +146,7 @@ public abstract class CukeStepDefsAbstract {
     /**
      * Convenience method
      */
-    public void assertIsSatisfied() {
+    public void assertMocksSatisfied() {
         scenarioExecution().assertIsSatisfied();
     }
     

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java b/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
index 05a20fc..6c9280b 100644
--- a/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
+++ b/example/application/quickstart_wicket_restful_jdo/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
@@ -49,13 +49,13 @@ public class ToDoItemsFixture extends AbstractFixture {
 
         createToDoItemForUser("Buy milk", Category.Domestic, user, daysFromToday(0), new BigDecimal("0.75"));
         createToDoItemForUser("Buy bread", Category.Domestic, user, daysFromToday(0), new BigDecimal("1.75"));
-        createToDoItemForUser("Buy stamps", Category.Domestic, user, daysFromToday(0), new BigDecimal("10.00"));
+        createToDoItemForUser("Buy stamps", Category.Domestic, user, daysFromToday(0), new BigDecimal("10.00")).setComplete(true);
         createToDoItemForUser("Pick up laundry", Category.Domestic, user, daysFromToday(6), new BigDecimal("7.50"));
         createToDoItemForUser("Sharpen knives", Category.Domestic, user, daysFromToday(14), null);
         
         createToDoItemForUser("Write to penpal", Category.Other, user, null, null);
         
-        createToDoItemForUser("Write blog post", Category.Professional, user, daysFromToday(7), null);
+        createToDoItemForUser("Write blog post", Category.Professional, user, daysFromToday(7), null).setComplete(true);
         createToDoItemForUser("Organize brown bag", Category.Professional, user, daysFromToday(14), null);
         createToDoItemForUser("Submit conference session", Category.Professional, user, daysFromToday(21), null);
         createToDoItemForUser("Stage Isis release", Category.Professional, user, null, null);

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml b/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
index abaaea2..26d95c0 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
@@ -37,6 +37,7 @@
                     <configuration>
                         <includes>
                             <include>**/*Test*.java</include>
+                            <include>**/*Specs*.java</include>
                         </includes>
                         <excludes>
                             <exclude>**/*Abstract*.java</exclude>

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/ToDoSystemInitializer.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/ToDoSystemInitializer.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/ToDoSystemInitializer.java
index 165f8b9..349fd34 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/ToDoSystemInitializer.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/ToDoSystemInitializer.java
@@ -1,18 +1,18 @@
-/*
- *  Copyright 2012-2013 Eurocommercial Properties NV
- *
- *  Licensed under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
  *
- *        http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
  */
 package integration;
 

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/BootstrapIntegrationStepDefs.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/BootstrapIntegrationStepDefs.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/BootstrapIntegrationStepDefs.java
index 2ad7014..6b3f690 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/BootstrapIntegrationStepDefs.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/BootstrapIntegrationStepDefs.java
@@ -1,18 +1,18 @@
-/*
- *  Copyright 2012-2013 Eurocommercial Properties NV
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
  *
- *  Licensed under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
  */
 package integration.specs.todoitem;
 

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.feature
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.feature b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.feature
new file mode 100644
index 0000000..c3e2f29
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.feature
@@ -0,0 +1,38 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+Feature: Find And Complete ToDo Items
+
+  # the scenario is listed twice here just to demonstrate that it
+  # can be run either at @unit-level scope (using mocks) or
+  # at @integration-level scope (against the running system).
+  
+  @unit
+  Scenario: Todo items once completed are no longer listed
+    Given there are a number of incomplete ToDo items
+    When  I choose the first of the incomplete items
+    And   mark the item as complete
+    Then  the item is no longer listed as incomplete 
+
+
+  @integration
+  Scenario: Todo items once completed are no longer listed
+    Given there are a number of incomplete ToDo items
+    When  I choose the first of the incomplete items
+    And   mark the item as complete
+    Then  the item is no longer listed as incomplete 
+
+    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.java
new file mode 100644
index 0000000..141e8dd
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindAndCompleteToDoItemsSpec.java
@@ -0,0 +1,37 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package integration.specs.todoitem;
+
+import cucumber.api.junit.Cucumber;
+
+import org.junit.runner.RunWith;
+
+
+/**
+ * Runs scenarios in corresponding <tt>.feature</tt> file. 
+ */
+@RunWith(Cucumber.class)
+@Cucumber.Options(
+        format = {
+                "html:target/cucumber-html-report"
+        },
+        strict = true,
+        tags = { "~@backlog", "~@ignore" })
+public class FindAndCompleteToDoItemsSpec {
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.feature
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.feature b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.feature
new file mode 100644
index 0000000..d37b2b5
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.feature
@@ -0,0 +1,34 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+Feature: Find completed ToDoItem and mark as not yet complete
+
+  # the scenario is listed twice here just to demonstrate that it
+  # can be run either at @unit-level scope (using mocks) or
+  # at @integration-level scope (against the running system).
+  
+  @unit
+  Scenario: Todo items can be uncompleted
+    Given a completed item
+    When  I mark the item as not yet complete
+    Then  the item is listed as incomplete 
+
+ 
+  @integration
+  Scenario: Todo items can be uncompleted
+    Given a completed ToDo item
+    When  I mark the item as not yet complete
+    Then  the item is listed as incomplete 

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.java
new file mode 100644
index 0000000..a3987ac
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/FindCompletedToDoItemAndMarkAsNotYetCompleteSpec.java
@@ -0,0 +1,37 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package integration.specs.todoitem;
+
+import cucumber.api.junit.Cucumber;
+
+import org.junit.runner.RunWith;
+
+
+/**
+ * Runs scenarios in all <tt>.feature</tt> files in this package. 
+ */
+@RunWith(Cucumber.class)
+@Cucumber.Options(
+        format = {
+                "html:target/cucumber-html-report"
+        },
+        strict = true,
+        tags = { "~@backlog", "~@ignore" })
+public class FindCompletedToDoItemAndMarkAsNotYetCompleteSpec {
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.feature
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.feature b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.feature
deleted file mode 100644
index da53c6f..0000000
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.feature
+++ /dev/null
@@ -1,13 +0,0 @@
-Feature: Find And Complete ToDo Items
-
-  # can either run at unit-level scope or integration-level scope
-  
-  #@integration
-  @unit
-  Scenario: Todo items once completed are no longer listed
-    Given there are a number of incomplete ToDo items
-    When  I choose the first one
-    And   mark it as complete
-    Then  the item is no longer listed as incomplete 
-
-

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.java
deleted file mode 100644
index 743c7a0..0000000
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpecs.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Copyright 2012-2013 Eurocommercial Properties NV
- *
- *  Licensed under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package integration.specs.todoitem;
-
-import cucumber.api.junit.Cucumber;
-
-import org.junit.runner.RunWith;
-
-
-/**
- * Runs all scenarios in corresponding <tt>.feature</tt> file. 
- */
-@RunWith(Cucumber.class)
-@Cucumber.Options(
-        format = {
-                "html:target/cucumber-html-report"
-        },
-        strict = true,
-        tags = { "~@backlog" })
-public class ToDoItemSpecs {
-
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/3d271d24/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemStepDefs.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemStepDefs.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemStepDefs.java
index b97e05e..680d79f 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemStepDefs.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemStepDefs.java
@@ -1,29 +1,28 @@
-/*
- *  Copyright 2012-2013 Eurocommercial Properties NV
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
  *
- *  Licensed under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
  */
 package integration.specs.todoitem;
 
-import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.*;
 import static org.junit.Assert.assertThat;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
@@ -37,7 +36,7 @@ import dom.todo.ToDoItems;
 import fixture.todo.ToDoItemsFixture;
 
 import org.jmock.Expectations;
-import org.jmock.Mockery;
+import org.junit.Assert;
 
 import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
 import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
@@ -48,8 +47,6 @@ public class ToDoItemStepDefs extends CukeStepDefsAbstract {
 
     // //////////////////////////////////////
     
-    private List<ToDoItem> items;
-
     @Before({"@unit"})
     public void beforeScenarioUnitScope() {
         before(ScenarioExecutionScope.UNIT);
@@ -62,29 +59,21 @@ public class ToDoItemStepDefs extends CukeStepDefsAbstract {
 
     @After
     public void afterScenario(cucumber.api.Scenario sc) {
+        assertMocksSatisfied();
         after(sc);
     }
 
     // //////////////////////////////////////
     
-    
 
     @Before(value={"@unit"}, order=20000)
     public void unitFixtures() throws Throwable {
         final InMemoryDB inMemoryDB = new InMemoryDBForToDoApp(this.scenarioExecution());
-        final ToDoItem t1 = inMemoryDB.getElseCreate(ToDoItem.class, "Write blog post");
-        final ToDoItem t2 = inMemoryDB.getElseCreate(ToDoItem.class, "Pick up bread");
-        items = Arrays.asList(t1, t2);
-    }
-
-    private static ArrayList<ToDoItem> notYetComplete(List<ToDoItem> items) {
-        return Lists.newArrayList(Iterables.filter(items, new Predicate<ToDoItem>(){
-
-            @Override
-            public boolean apply(ToDoItem input) {
-                return !input.isComplete();
-            }
-        }));
+        inMemoryDB.getElseCreate(ToDoItem.class, "Write blog post");
+        inMemoryDB.getElseCreate(ToDoItem.class, "Pick up bread");
+        final ToDoItem t3 = inMemoryDB.getElseCreate(ToDoItem.class, "Pick up butter");
+        t3.setComplete(true);
+        putVar("isis", "in-memory-db", inMemoryDB);
     }
 
     @Before(value={"@integration"}, order=20000)
@@ -97,51 +86,115 @@ public class ToDoItemStepDefs extends CukeStepDefsAbstract {
 
     @Given("^there are a number of incomplete ToDo items$")
     public void there_are_a_number_of_incomplete_ToDo_items() throws Throwable {
-        checking(new Expectations() {
-            {
-                allowing(service(ToDoItems.class)).notYetComplete();
-                will(returnValue(notYetComplete(items)));
-            }
-        });
-
-        final List<ToDoItem> notYetComplete = service(ToDoItems.class).notYetComplete();
-        assertThat(notYetComplete.isEmpty(), is(false));
-        put("list", "notYetComplete", notYetComplete);
+        if(supportsMocks()) {
+            checking(new Expectations() {
+                {
+                    allowing(service(ToDoItems.class)).notYetComplete();
+                    will(returnValue(notYetCompleteItems()));
+                }
+            });
+        }
+        try {
+            final List<ToDoItem> notYetComplete = service(ToDoItems.class).notYetComplete();
+            assertThat(notYetComplete.isEmpty(), is(false));
+            putVar("list", "notYetCompleteItems", notYetComplete);
+            
+        } finally {
+            assertMocksSatisfied();
+        }
     }
     
-    @When("^I choose the first one$")
+    @When("^I choose the first of the incomplete items$")
     public void I_choose_the_first_one() throws Throwable {
         @SuppressWarnings("unchecked")
-        List<ToDoItem> notYetComplete = get(null, "notYetComplete", List.class);
+        List<ToDoItem> notYetComplete = getVar(null, "notYetCompleteItems", List.class);
         assertThat(notYetComplete.isEmpty(), is(false));
         
-        put("todo", "firstToDo", notYetComplete.get(0));
+        putVar("todo", "toDoItem", notYetComplete.get(0));
     }
     
-    @When("^mark it as complete$")
+    @When("^mark the item as complete$")
     public void mark_it_as_complete() throws Throwable {
-        ToDoItem toDoItem = get(null, "firstToDo", ToDoItem.class);
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
         wrap(toDoItem).completed();
     }
     
     @Then("^the item is no longer listed as incomplete$")
     public void the_item_is_no_longer_listed_as_incomplete() throws Throwable {
-        assertIsSatisfied();
-        Mockery m;
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        whetherNotYetCompletedContains(toDoItem, false);
+    }
+
+    
+    
+    @Given("^.*completed .*item$")
+    public void a_completed_ToDo_item() throws Throwable {
+        if(supportsMocks()) {
+            checking(new Expectations(){{
+                allowing(service(ToDoItems.class)).allToDos();
+                will(returnValue(findItems(Predicates.<ToDoItem>alwaysTrue()) ));
+            }});
+        }
+        try {
+            final List<ToDoItem> allToDos = service(ToDoItems.class).allToDos();
+            for (ToDoItem toDoItem : allToDos) {
+                if(toDoItem.isComplete()) {
+                    putVar("todo", "toDoItem", toDoItem);
+                    return;
+                }
+            }
+            Assert.fail("could not locate any completed ToDo items");
+        } finally {
+            assertMocksSatisfied();
+        }
+    }
+
+    @When("^I mark the .*item as not yet complete$")
+    public void I_mark_it_as_not_yet_complete() throws Throwable {
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        assertThat(toDoItem.isComplete(), is(true));
         
-        final ArrayList<ToDoItem> notYetCompleteItems = notYetComplete(items);
-        checking(new Expectations() {
-            {
-                oneOf(service(ToDoItems.class)).notYetComplete();
-                will(returnValue(notYetCompleteItems));
+        toDoItem.setComplete(false);
+    }
+
+    @Then("^the .*item is listed as incomplete$")
+    public void the_item_is_listed_as_incomplete() throws Throwable {
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        whetherNotYetCompletedContains(toDoItem, true);
+    }
+
+    private void whetherNotYetCompletedContains(ToDoItem toDoItem, final boolean whetherContained) {
+        if(supportsMocks()) {
+            final List<ToDoItem> notYetCompleteItems = notYetCompleteItems();
+            checking(new Expectations() {
+                {
+                    oneOf(service(ToDoItems.class)).notYetComplete();
+                    will(returnValue(notYetCompleteItems));
+                }
+            });
+        }
+        try {
+            final List<ToDoItem> notYetComplete = service(ToDoItems.class).notYetComplete();
+            assertThat(notYetComplete.contains(toDoItem), is(whetherContained));
+        } finally {
+            assertMocksSatisfied();
+        }
+    }
+
+
+    // helper
+    private List<ToDoItem> notYetCompleteItems() {
+        return findItems(new Predicate<ToDoItem>(){
+            @Override
+            public boolean apply(ToDoItem input) {
+                return !input.isComplete();
             }
         });
+    }
 
-        final List<ToDoItem> notYetComplete = service(ToDoItems.class).notYetComplete();
-        ToDoItem toDoItem = get(null, "firstToDo", ToDoItem.class);
-        
-        assertThat(notYetComplete.contains(toDoItem), is(false));
+    private List<ToDoItem> findItems(final Predicate<ToDoItem> predicate) {
+        final InMemoryDB inMemoryDB = getVar("isis", "in-memory-db", InMemoryDB.class);
+        final List<ToDoItem> items = inMemoryDB.findAll(ToDoItem.class);
+        return Lists.newArrayList(Iterables.filter(items, predicate));
     }
-    
-    
 }