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/18 07:06:41 UTC
git commit: ISIS-463: ensuring StepDefs reusable across features
Updated Branches:
refs/heads/master 94ccda3a3 -> ab83b2600
ISIS-463: ensuring StepDefs reusable across features
* renamed "StepDefs" to "Glue" throughout (Cukes uses this term in its runner, the word "Specs" and "StepDefs" are too similar to each other)
* moved glue to separate directories to specs
* updated Specs runner to pick up glue from that package (and any subpackages)
* changed CukeGlueAbstract so that it doesn't hold the ScenarioExecution as a field, instead gets from the ThreadLocal
- needed so can do bootstrapping glue separately from other glue steps
* created separate glue for a "catalog of fixtures", selected using a tag
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/ab83b260
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/ab83b260
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/ab83b260
Branch: refs/heads/master
Commit: ab83b26002e4ca7aecba7709bd29ec0f0bb312d3
Parents: 94ccda3
Author: Dan Haywood <da...@apache.org>
Authored: Thu Jul 18 06:06:10 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Thu Jul 18 06:06:10 2013 +0100
----------------------------------------------------------------------
.../IntegrationTestAbstract.java | 8 +-
.../ScenarioExecutionForIntegration.java | 16 +-
.../scenarios/ScenarioExecution.java | 19 +-
.../scenarios/ScenarioExecutionForUnit.java | 2 +-
.../specsupport/specs/CukeGlueAbstract.java | 348 ++++++++++++++++++
.../specsupport/specs/CukeStepDefsAbstract.java | 352 -------------------
.../integration/glue/BootstrappingGlue.java | 55 +++
.../integration/glue/CatalogOfFixturesGlue.java | 47 +++
.../integration/glue/InMemoryDBForToDoApp.java | 40 +++
.../integration/glue/todoitem/ToDoItemGlue.java | 156 ++++++++
.../integration/specs/InMemoryDBForToDoApp.java | 40 ---
.../ToDoItemSpec_findAndComplete.feature | 1 +
.../todoitem/ToDoItemSpec_findAndComplete.java | 1 +
...findCompletedAndMarkAsNotYetComplete.feature | 1 +
...ec_findCompletedAndMarkAsNotYetComplete.java | 1 +
.../specs/todoitem/ToDoItemStepDefs.java | 206 -----------
16 files changed, 674 insertions(+), 619 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/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 97f1ac5..e438849 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
@@ -27,7 +27,7 @@ import org.junit.runners.model.Statement;
import org.apache.isis.applib.DomainObjectContainer;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
-import org.apache.isis.core.specsupport.specs.CukeStepDefsAbstract;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
@@ -35,15 +35,15 @@ import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
* Base class for integration tests.
*
* <p>
- * There is substantial overlap with {@link CukeStepDefsAbstract}, and it would be possible to factor
+ * There is substantial overlap with {@link CukeGlueAbstract}, and it would be possible to factor
* out a common base class. Both delegate to an underlying {@link ScenarioExecution}, and provide
* a bunch of helper methods. The reason this has not been done is mostly to make it easier to see
* the equivalence of these two classes.
*
* <p>
- * The only real differences between this class and {@link CukeStepDefsAbstract} is that this class
+ * The only real differences between this class and {@link CukeGlueAbstract} is that this class
* uses JUnit rules to automatically perform {@link IsisTransactionRule transaction management} and
- * uses JUnit rules for {@link ExpectedException exception handling}. In {@link CukeStepDefsAbstract} these
+ * uses JUnit rules for {@link ExpectedException exception handling}. In {@link CukeGlueAbstract} these
* are required (by Cucumber-JVM) to be explicitly handled in the step definitions.
*/
public abstract class IntegrationTestAbstract {
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/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 4330e5a..68476b5 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,23 +16,11 @@
*/
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;
-import org.apache.isis.core.specsupport.scenarios.DomainServiceProvider;
import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
-import org.apache.isis.core.wrapper.WrapperFactoryDefault;
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
/**
@@ -50,7 +38,7 @@ public class ScenarioExecutionForIntegration extends ScenarioExecution {
private IsisSystemForTest isft;
public ScenarioExecutionForIntegration() {
- super(IsisSystemForTest.get());
+ super(IsisSystemForTest.get(), ScenarioExecutionScope.INTEGRATION);
this.isft = (IsisSystemForTest) dsp;
}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/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 59864e4..33f7575 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
@@ -59,7 +59,11 @@ import org.apache.isis.applib.services.wrapper.WrapperFactory;
public abstract class ScenarioExecution {
private static ThreadLocal<ScenarioExecution> current = new ThreadLocal<ScenarioExecution>();
-
+
+ public static ScenarioExecution peek() {
+ return current.get();
+ }
+
public static ScenarioExecution current() {
final ScenarioExecution execution = current.get();
if(execution == null) {
@@ -72,12 +76,21 @@ public abstract class ScenarioExecution {
// //////////////////////////////////////
protected final DomainServiceProvider dsp;
+ private final ScenarioExecutionScope scope;
- protected ScenarioExecution(final DomainServiceProvider dsp) {
+ protected ScenarioExecution(final DomainServiceProvider dsp, ScenarioExecutionScope scope) {
this.dsp = dsp;
+ this.scope = scope;
current.set(this);
}
+ public boolean ofScope(ScenarioExecutionScope scope) {
+ return this.scope == scope;
+ }
+
+
+ // //////////////////////////////////////
+
/**
* Returns a domain service of the specified type, ensuring that
* it is available.
@@ -409,4 +422,6 @@ public abstract class ScenarioExecution {
}
+
+
}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/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 b1768b3..1d2accd 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
@@ -41,7 +41,7 @@ public class ScenarioExecutionForUnit extends ScenarioExecution {
this(new DomainServiceProviderMockery());
}
private ScenarioExecutionForUnit(DomainServiceProviderMockery dspm) {
- super(dspm);
+ super(dspm, ScenarioExecutionScope.UNIT);
this.dspm = dspm.init(this);
}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract.java
----------------------------------------------------------------------
diff --git a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract.java b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract.java
new file mode 100644
index 0000000..55618c5
--- /dev/null
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract.java
@@ -0,0 +1,348 @@
+/**
+ * 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 org.apache.isis.core.specsupport.specs;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+
+import org.jmock.Sequence;
+import org.jmock.States;
+import org.jmock.internal.ExpectationBuilder;
+import org.junit.Assert;
+
+import cucumber.api.DataTable;
+import cucumber.api.java.Before;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionForUnit;
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
+
+
+/**
+ * Base class for Cucumber-JVM step definitions.
+ *
+ * <p>
+ * Simply declares that an instance of {@link ScenarioExecution} (or a subclass)
+ * must be instantiated by the Cucumber-JVM runtime and injected into the step definitions.
+ */
+public abstract class CukeGlueAbstract {
+
+ /**
+ * Access the {@link ScenarioExecution} as setup through a previous call to {@link #before(ScenarioExecutionScope)}.
+ *
+ * <p>
+ * This corresponds, broadly, to the (Ruby) Cucumber's "World" object.
+ */
+ protected ScenarioExecution scenarioExecution() {
+ if(ScenarioExecution.current() == null) {
+ throw new IllegalStateException("The scenario execution has not been set up; call #before(ScenarioExecutionScope) first");
+ }
+ return ScenarioExecution.current();
+ }
+
+ // //////////////////////////////////////
+
+ /**
+ * Intended to be called at the beginning of any 'when' (after all the 'given's)
+ * or at the beginning of any 'then' (after all the 'when's)
+ *
+ * <p>
+ * Simply {@link ScenarioExecution#endTran(boolean) ends any existing transaction} and
+ * then {@link ScenarioExecution#beginTran() starts a new one}.
+ */
+ protected void nextTransaction() {
+ scenarioExecution().endTran(true);
+ scenarioExecution().beginTran();
+ }
+
+
+ // //////////////////////////////////////
+
+ /**
+ * Convenience method
+ */
+ public Object getVar(String type, String id) {
+ return scenarioExecution().getVar(type, id);
+ }
+
+ /**
+ * Convenience method
+ */
+ public <X> X getVar(String type, String id, Class<X> cls) {
+ return scenarioExecution().getVar(type, id ,cls);
+ }
+
+ /**
+ * Convenience method
+ */
+ 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
+ */
+ protected <T> T service(Class<T> cls) {
+ return scenarioExecution().service(cls);
+ }
+
+ /**
+ * Convenience method
+ */
+ protected DomainObjectContainer container() {
+ return scenarioExecution().container();
+ }
+
+ /**
+ * Convenience method
+ */
+ protected WrapperFactory wrapperFactory() {
+ return scenarioExecution().wrapperFactory();
+ }
+
+ /**
+ * Convenience method
+ */
+ protected <T> T wrap(T obj) {
+ return wrapperFactory().wrap(obj);
+ }
+
+ /**
+ * Convenience method
+ */
+ protected <T> T unwrap(T obj) {
+ return wrapperFactory().unwrap(obj);
+ }
+
+ /**
+ * Convenience method
+ * @return
+ */
+ public boolean supportsMocks() {
+ return scenarioExecution().supportsMocks();
+ }
+
+ /**
+ * Convenience method
+ */
+ public void checking(ExpectationBuilder expectations) {
+ scenarioExecution().checking(expectations);
+ }
+
+ /**
+ * Convenience method
+ */
+ public void assertMocksSatisfied() {
+ scenarioExecution().assertIsSatisfied();
+ }
+
+ /**
+ * Convenience method
+ */
+ public Sequence sequence(String name) {
+ return scenarioExecution().sequence(name);
+ }
+
+ /**
+ * Convenience method
+ */
+ public States states(String name) {
+ return scenarioExecution().states(name);
+ }
+
+ // //////////////////////////////////////
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static void assertTableEquals(final List listOfExpecteds, final Iterable iterableOfActuals) {
+ final List<Object> listOfActuals = Lists.newArrayList(iterableOfActuals);
+ assertThat(listOfActuals.size(), is(listOfExpecteds.size()));
+
+ final StringBuilder buf = new StringBuilder();
+ for (int i=0; i<listOfActuals.size(); i++) {
+
+ final Object actual = listOfActuals.get(i);
+ final Object expected = listOfExpecteds.get(i);
+
+ final Field[] expectedFields = expected.getClass().getDeclaredFields();
+ for (Field field : expectedFields) {
+ final String propertyName = field.getName();
+ final Object actualProp = getProperty(actual, propertyName );
+ final Object expectedProp = getProperty(expected, propertyName);
+
+ if(!Objects.equal(actualProp, expectedProp)) {
+ buf.append("#" + i + ": " + propertyName + ": " + expectedProp + " vs " + actualProp).append("\n");
+ }
+ }
+ }
+ if(buf.length() != 0) {
+ Assert.fail("\n" + buf.toString());
+ }
+ }
+
+
+ private static Object getProperty(Object obj, String propertyName) {
+ if(obj == null) {
+ return null;
+ }
+ final Class<? extends Object> cls = obj.getClass();
+ try {
+ final String methodName = "get" + capitalize(propertyName);
+ final Method method = cls.getMethod(methodName, new Class[]{});
+ if(method != null) {
+ return method.invoke(obj);
+ }
+ } catch (Exception e) {
+ // continue
+ }
+
+ try {
+ final String methodName = "is" + capitalize(propertyName);
+ final Method method = cls.getMethod(methodName, new Class[]{});
+ if(method != null) {
+ return method.invoke(obj);
+ }
+ } catch (Exception e) {
+ // continue
+ }
+
+ try {
+ final Field field = cls.getDeclaredField(propertyName);
+ if(field != null) {
+ if(!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ return field.get(obj);
+ }
+ } catch (Exception e) {
+ // continue
+ }
+
+ Assert.fail("Unable to locate property '" + propertyName + "' in object " + obj);
+ return null;
+ }
+
+ private static String capitalize(final String str) {
+ if (str == null || str.length() == 0) {
+ return str;
+ }
+ if (str.length() == 1) {
+ return str.toUpperCase();
+ }
+ return Character.toUpperCase(str.charAt(0)) + str.substring(1);
+ }
+
+
+ // //////////////////////////////////////
+
+ /**
+ * Indicate that a scenario is starting, and specify the {@link ScenarioExecutionScope scope}
+ * at which to run the scenario.
+ *
+ * <p>
+ * This method should be called from a "before" hook (a method annotated with
+ * Cucumber's {@link Before} annotation, in a step definition subclass. The tag
+ * should be appropriate for the scope specified. Typically this method should be delegated to
+ * twice, in two mutually exclusive before hooks.
+ *
+ * <p>
+ * Calling this method makes the {@link ScenarioExecution} available (via {@link #scenarioExecution()}).
+ * It also delegates to the scenario to {@link ScenarioExecution#beginTran() begin the transaction}.
+ * (Whether this actually does anything depends in implementation of the {@link ScenarioExecution}).
+ *
+ * <p>
+ * The boilerplate (to copy-n-paste as required) is:
+ * <pre>
+ * @cucumber.api.java.Before("@unit")
+ * public void beforeScenarioUnitScope() {
+ * before(ScenarioExecutionScope.UNIT);
+ * }
+ * @cucumber.api.java.Before("@integration")
+ * public void beforeScenarioIntegrationScope() {
+ * before(ScenarioExecutionScope.INTEGRATION);
+ * }
+ * </pre>
+ * The built-in {@link ScenarioExecutionScope#UNIT unit}-level scope will instantiate a
+ * {@link ScenarioExecutionForUnit}, while the built-in
+ * {@link ScenarioExecutionScope#INTEGRATION integration}-level scope instantiates
+ * <tt>ScenarioExecutionForIntegration</tt> (from the <tt>isis-core-integtestsupport</tt> module).
+ * The former provides access to domain services as mocks, whereas the latter wraps a running
+ * <tt>IsisSystemForTest</tt>.
+ *
+ * <p>
+ * If need be, it is also possible to define custom scopes, with a different implementation of
+ * {@link ScenarioExecution}. This might be done when unit testing where a large number of specs
+ * have similar expectations needing to be set on the mock domain services.
+ *
+ * <p>
+ * Not every class holding step definitions should have these hooks, only those that correspond to the logical
+ * beginning and end of scenario. As such, this method may only be called once per scenario execution
+ * (and fails fast if called more than once).
+ */
+ protected void before(ScenarioExecutionScope scope) {
+ final ScenarioExecution se = ScenarioExecution.peek();
+ if(se != null && se.ofScope(scope)) {
+ // don't trample over an existing, compatible ScenarioExecution.
+ return;
+ }
+ final ScenarioExecution scenarioExecution = scope.instantiate();
+ scenarioExecution.beginTran();
+ }
+
+ /**
+ * Indicate that a scenario is ending; the {@link ScenarioExecution} is discarded and no
+ * longer {@link #scenarioExecution() available}.
+ *
+ * <p>
+ * Before being discarded, the {@link ScenarioExecution} is delegated to
+ * in order to {@link ScenarioExecution#endTran(boolean) end the transaction}.
+ * (Whether this actually does anything depends in implementation of the {@link ScenarioExecution}).
+ *
+ * <p>
+ * The boilerplate (to copy-n-paste as required) is:
+ * <pre>
+ * @cucumber.api.java.After
+ * public void afterScenario(cucumber.api.Scenario sc) {
+ * after(sc);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Not every class holding step definitions should have this hook, only those that correspond to the logical
+ * beginning and end of scenario. As such, this method may only be called once per scenario execution
+ * (and fails fast if called more than once).
+ */
+ public void after(cucumber.api.Scenario sc) {
+ ScenarioExecution.current().endTran(!sc.isFailed());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/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
deleted file mode 100644
index c6cc3ca..0000000
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeStepDefsAbstract.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/**
- * 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 org.apache.isis.core.specsupport.specs;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.List;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-
-import org.jmock.Sequence;
-import org.jmock.States;
-import org.jmock.internal.ExpectationBuilder;
-import org.junit.Assert;
-
-import cucumber.api.DataTable;
-import cucumber.api.java.Before;
-
-import org.apache.isis.applib.DomainObjectContainer;
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
-import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionForUnit;
-import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
-
-
-/**
- * Base class for Cucumber-JVM step definitions.
- *
- * <p>
- * Simply declares that an instance of {@link ScenarioExecution} (or a subclass)
- * must be instantiated by the Cucumber-JVM runtime and injected into the step definitions.
- */
-public abstract class CukeStepDefsAbstract {
-
- private ScenarioExecution scenarioExecution;
-
- /**
- * Access the {@link ScenarioExecution} as setup through a previous call to {@link #before(ScenarioExecutionScope)}.
- *
- * <p>
- * This corresponds, broadly, to the (Ruby) Cucumber's "World" object.
- */
- protected ScenarioExecution scenarioExecution() {
- if(scenarioExecution == null) {
- throw new IllegalStateException("The scenario execution has not been set up; call #before(ScenarioExecutionScope) first");
- }
- return scenarioExecution;
- }
-
- // //////////////////////////////////////
-
- /**
- * Intended to be called at the beginning of any 'when' (after all the 'given's)
- * or at the beginning of any 'then' (after all the 'when's)
- *
- * <p>
- * Simply {@link ScenarioExecution#endTran(boolean) ends any existing transaction} and
- * then {@link ScenarioExecution#beginTran() starts a new one}.
- */
- protected void nextTransaction() {
- scenarioExecution().endTran(true);
- scenarioExecution().beginTran();
- }
-
-
- // //////////////////////////////////////
-
- /**
- * Convenience method
- */
- public Object getVar(String type, String id) {
- return scenarioExecution().getVar(type, id);
- }
-
- /**
- * Convenience method
- */
- public <X> X getVar(String type, String id, Class<X> cls) {
- return scenarioExecution().getVar(type, id ,cls);
- }
-
- /**
- * Convenience method
- */
- 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
- */
- protected <T> T service(Class<T> cls) {
- return scenarioExecution().service(cls);
- }
-
- /**
- * Convenience method
- */
- protected DomainObjectContainer container() {
- return scenarioExecution().container();
- }
-
- /**
- * Convenience method
- */
- protected WrapperFactory wrapperFactory() {
- return scenarioExecution().wrapperFactory();
- }
-
- /**
- * Convenience method
- */
- protected <T> T wrap(T obj) {
- return wrapperFactory().wrap(obj);
- }
-
- /**
- * Convenience method
- */
- protected <T> T unwrap(T obj) {
- return wrapperFactory().unwrap(obj);
- }
-
- /**
- * Convenience method
- * @return
- */
- public boolean supportsMocks() {
- return scenarioExecution().supportsMocks();
- }
-
- /**
- * Convenience method
- */
- public void checking(ExpectationBuilder expectations) {
- scenarioExecution().checking(expectations);
- }
-
- /**
- * Convenience method
- */
- public void assertMocksSatisfied() {
- scenarioExecution().assertIsSatisfied();
- }
-
- /**
- * Convenience method
- */
- public Sequence sequence(String name) {
- return scenarioExecution().sequence(name);
- }
-
- /**
- * Convenience method
- */
- public States states(String name) {
- return scenarioExecution().states(name);
- }
-
- // //////////////////////////////////////
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static void assertTableEquals(final List listOfExpecteds, final Iterable iterableOfActuals) {
- final List<Object> listOfActuals = Lists.newArrayList(iterableOfActuals);
- assertThat(listOfActuals.size(), is(listOfExpecteds.size()));
-
- final StringBuilder buf = new StringBuilder();
- for (int i=0; i<listOfActuals.size(); i++) {
-
- final Object actual = listOfActuals.get(i);
- final Object expected = listOfExpecteds.get(i);
-
- final Field[] expectedFields = expected.getClass().getDeclaredFields();
- for (Field field : expectedFields) {
- final String propertyName = field.getName();
- final Object actualProp = getProperty(actual, propertyName );
- final Object expectedProp = getProperty(expected, propertyName);
-
- if(!Objects.equal(actualProp, expectedProp)) {
- buf.append("#" + i + ": " + propertyName + ": " + expectedProp + " vs " + actualProp).append("\n");
- }
- }
- }
- if(buf.length() != 0) {
- Assert.fail("\n" + buf.toString());
- }
- }
-
-
- private static Object getProperty(Object obj, String propertyName) {
- if(obj == null) {
- return null;
- }
- final Class<? extends Object> cls = obj.getClass();
- try {
- final String methodName = "get" + capitalize(propertyName);
- final Method method = cls.getMethod(methodName, new Class[]{});
- if(method != null) {
- return method.invoke(obj);
- }
- } catch (Exception e) {
- // continue
- }
-
- try {
- final String methodName = "is" + capitalize(propertyName);
- final Method method = cls.getMethod(methodName, new Class[]{});
- if(method != null) {
- return method.invoke(obj);
- }
- } catch (Exception e) {
- // continue
- }
-
- try {
- final Field field = cls.getDeclaredField(propertyName);
- if(field != null) {
- if(!field.isAccessible()) {
- field.setAccessible(true);
- }
- return field.get(obj);
- }
- } catch (Exception e) {
- // continue
- }
-
- Assert.fail("Unable to locate property '" + propertyName + "' in object " + obj);
- return null;
- }
-
- private static String capitalize(final String str) {
- if (str == null || str.length() == 0) {
- return str;
- }
- if (str.length() == 1) {
- return str.toUpperCase();
- }
- return Character.toUpperCase(str.charAt(0)) + str.substring(1);
- }
-
-
- // //////////////////////////////////////
-
- /**
- * Indicate that a scenario is starting, and specify the {@link ScenarioExecutionScope scope}
- * at which to run the scenario.
- *
- * <p>
- * This method should be called from a "before" hook (a method annotated with
- * Cucumber's {@link Before} annotation, in a step definition subclass. The tag
- * should be appropriate for the scope specified. Typically this method should be delegated to
- * twice, in two mutually exclusive before hooks.
- *
- * <p>
- * Calling this method makes the {@link ScenarioExecution} available (via {@link #scenarioExecution()}).
- * It also delegates to the scenario to {@link ScenarioExecution#beginTran() begin the transaction}.
- * (Whether this actually does anything depends in implementation of the {@link ScenarioExecution}).
- *
- * <p>
- * The boilerplate (to copy-n-paste as required) is:
- * <pre>
- * @cucumber.api.java.Before("@unit")
- * public void beforeScenarioUnitScope() {
- * before(ScenarioExecutionScope.UNIT);
- * }
- * @cucumber.api.java.Before("@integration")
- * public void beforeScenarioIntegrationScope() {
- * before(ScenarioExecutionScope.INTEGRATION);
- * }
- * </pre>
- * The built-in {@link ScenarioExecutionScope#UNIT unit}-level scope will instantiate a
- * {@link ScenarioExecutionForUnit}, while the built-in
- * {@link ScenarioExecutionScope#INTEGRATION integration}-level scope instantiates
- * <tt>ScenarioExecutionForIntegration</tt> (from the <tt>isis-core-integtestsupport</tt> module).
- * The former provides access to domain services as mocks, whereas the latter wraps a running
- * <tt>IsisSystemForTest</tt>.
- *
- * <p>
- * If need be, it is also possible to define custom scopes, with a different implementation of
- * {@link ScenarioExecution}. This might be done when unit testing where a large number of specs
- * have similar expectations needing to be set on the mock domain services.
- *
- * <p>
- * Not every class holding step definitions should have these hooks, only those that correspond to the logical
- * beginning and end of scenario. As such, this method may only be called once per scenario execution
- * (and fails fast if called more than once).
- */
- protected void before(ScenarioExecutionScope scope) {
- if(scenarioExecution != null) {
- throw new IllegalStateException("Scenario execution scope has already been set");
- }
- scenarioExecution = scope.instantiate();
- scenarioExecution.beginTran();
- }
-
- /**
- * Indicate that a scenario is ending; the {@link ScenarioExecution} is discarded and no
- * longer {@link #scenarioExecution() available}.
- *
- * <p>
- * Before being discarded, the {@link ScenarioExecution} is delegated to
- * in order to {@link ScenarioExecution#endTran(boolean) end the transaction}.
- * (Whether this actually does anything depends in implementation of the {@link ScenarioExecution}).
- *
- * <p>
- * The boilerplate (to copy-n-paste as required) is:
- * <pre>
- * @cucumber.api.java.After
- * public void afterScenario(cucumber.api.Scenario sc) {
- * after(sc);
- * }
- * </pre>
- *
- * <p>
- * Not every class holding step definitions should have this hook, only those that correspond to the logical
- * beginning and end of scenario. As such, this method may only be called once per scenario execution
- * (and fails fast if called more than once).
- */
- public void after(cucumber.api.Scenario sc) {
- if(scenarioExecution == null) {
- throw new IllegalStateException("Scenario execution is not set");
- }
- scenarioExecution.endTran(!sc.isFailed());
- scenarioExecution = null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/BootstrappingGlue.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/BootstrappingGlue.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/BootstrappingGlue.java
new file mode 100644
index 0000000..b7f2ec6
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/BootstrappingGlue.java
@@ -0,0 +1,55 @@
+/**
+ * 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.glue;
+
+import integration.ToDoSystemInitializer;
+import cucumber.api.java.After;
+import cucumber.api.java.Before;
+
+import org.apache.log4j.PropertyConfigurator;
+
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
+
+public class BootstrappingGlue extends CukeGlueAbstract {
+
+ // //////////////////////////////////////
+
+ @Before(value={"@unit"}, order=100)
+ public void beforeScenarioUnitScope() {
+ before(ScenarioExecutionScope.UNIT);
+ }
+
+ @Before(value={"@integration"}, order=100)
+ public void beforeScenarioIntegrationScope() {
+ PropertyConfigurator.configure("logging.properties");
+ ToDoSystemInitializer.initIsft();
+
+ before(ScenarioExecutionScope.INTEGRATION);
+ }
+
+ @After
+ public void afterScenario(cucumber.api.Scenario sc) {
+ assertMocksSatisfied();
+ after(sc);
+ }
+
+ // //////////////////////////////////////
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java
new file mode 100644
index 0000000..9115a71
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java
@@ -0,0 +1,47 @@
+/**
+ * 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.glue;
+
+import cucumber.api.java.Before;
+import dom.todo.ToDoItem;
+import fixture.todo.ToDoItemsFixture;
+
+import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
+
+public class CatalogOfFixturesGlue extends CukeGlueAbstract {
+
+
+ @Before(value={"@unit", "@ToDoItemsFixture"}, order=20000)
+ public void unitFixtures() throws Throwable {
+ final InMemoryDB inMemoryDB = new InMemoryDBForToDoApp(this.scenarioExecution());
+ 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", "@ToDoItemsFixture"}, order=20000)
+ public void integrationFixtures() throws Throwable {
+ scenarioExecution().install(new ToDoItemsFixture());
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java
new file mode 100644
index 0000000..04dcfb6
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java
@@ -0,0 +1,40 @@
+/**
+ * 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.glue;
+
+import dom.todo.ToDoItem;
+
+import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
+
+public class InMemoryDBForToDoApp extends InMemoryDB {
+
+ public InMemoryDBForToDoApp(ScenarioExecution scenarioExecution) {
+ super(scenarioExecution);
+ }
+
+ /**
+ * Hook to initialize if possible.
+ */
+ @Override
+ protected void init(Object obj, String str) {
+ if(obj instanceof ToDoItem) {
+ ToDoItem toDoItem = (ToDoItem) obj;
+ toDoItem.setDescription(str);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
new file mode 100644
index 0000000..000674c
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
@@ -0,0 +1,156 @@
+/**
+ * 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.glue.todoitem;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+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;
+
+import cucumber.api.java.en.Given;
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItems;
+
+import org.jmock.Expectations;
+import org.junit.Assert;
+
+import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
+
+public class ToDoItemGlue extends CukeGlueAbstract {
+
+ @Given("^there are a number of incomplete ToDo items$")
+ public void there_are_a_number_of_incomplete_ToDo_items() throws Throwable {
+ 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 of the incomplete items$")
+ public void I_choose_the_first_one() throws Throwable {
+ @SuppressWarnings("unchecked")
+ List<ToDoItem> notYetComplete = getVar(null, "notYetCompleteItems", List.class);
+ assertThat(notYetComplete.isEmpty(), is(false));
+
+ putVar("todo", "toDoItem", notYetComplete.get(0));
+ }
+
+ @When("^mark the item as complete$")
+ public void mark_it_as_complete() throws Throwable {
+ 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 {
+ 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));
+
+ 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();
+ }
+ });
+ }
+
+ 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));
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/InMemoryDBForToDoApp.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/InMemoryDBForToDoApp.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/InMemoryDBForToDoApp.java
deleted file mode 100644
index 0d66741..0000000
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/InMemoryDBForToDoApp.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * 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;
-
-import dom.todo.ToDoItem;
-
-import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
-import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
-
-public class InMemoryDBForToDoApp extends InMemoryDB {
-
- public InMemoryDBForToDoApp(ScenarioExecution scenarioExecution) {
- super(scenarioExecution);
- }
-
- /**
- * Hook to initialize if possible.
- */
- @Override
- protected void init(Object obj, String str) {
- if(obj instanceof ToDoItem) {
- ToDoItem toDoItem = (ToDoItem) obj;
- toDoItem.setDescription(str);
- }
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
index c3e2f29..9fc1596 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+@ToDoItemsFixture
Feature: Find And Complete ToDo Items
# the scenario is listed twice here just to demonstrate that it
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.java
index 2440b7f..56776a5 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.java
@@ -29,6 +29,7 @@ import org.junit.runner.RunWith;
format = {
"html:target/cucumber-html-report"
},
+ glue="integration.glue",
strict = true,
tags = { "~@backlog", "~@ignore" })
public class ToDoItemSpec_findAndComplete {
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
index d37b2b5..bfa55d6 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+@ToDoItemsFixture
Feature: Find completed ToDoItem and mark as not yet complete
# the scenario is listed twice here just to demonstrate that it
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.java
index 4c8b1bb..97f8b71 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.java
@@ -29,6 +29,7 @@ import org.junit.runner.RunWith;
format = {
"html:target/cucumber-html-report"
},
+ glue="integration.glue",
strict = true,
tags = { "~@backlog", "~@ignore" })
public class ToDoItemSpec_findCompletedAndMarkAsNotYetComplete {
http://git-wip-us.apache.org/repos/asf/isis/blob/ab83b260/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
deleted file mode 100644
index 2d81b92..0000000
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/specs/todoitem/ToDoItemStepDefs.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- * 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 static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.assertThat;
-import integration.ToDoSystemInitializer;
-import integration.specs.InMemoryDBForToDoApp;
-
-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;
-
-import cucumber.api.java.After;
-import cucumber.api.java.Before;
-import cucumber.api.java.en.Given;
-import cucumber.api.java.en.Then;
-import cucumber.api.java.en.When;
-import dom.todo.ToDoItem;
-import dom.todo.ToDoItems;
-import fixture.todo.ToDoItemsFixture;
-
-import org.apache.log4j.PropertyConfigurator;
-import org.jmock.Expectations;
-import org.junit.Assert;
-
-import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
-import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
-import org.apache.isis.core.specsupport.specs.CukeStepDefsAbstract;
-
-public class ToDoItemStepDefs extends CukeStepDefsAbstract {
-
-
- // //////////////////////////////////////
-
- @Before({"@unit"})
- public void beforeScenarioUnitScope() {
- before(ScenarioExecutionScope.UNIT);
- }
-
- @Before(value={"@integration"}, order=100)
- public void beforeScenarioIntegrationScope() {
- PropertyConfigurator.configure("logging.properties");
- ToDoSystemInitializer.initIsft();
-
- before(ScenarioExecutionScope.INTEGRATION);
- }
-
- @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());
- 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)
- public void integrationFixtures() throws Throwable {
- scenarioExecution().install(new ToDoItemsFixture());
- }
-
- // //////////////////////////////////////
-
-
- @Given("^there are a number of incomplete ToDo items$")
- public void there_are_a_number_of_incomplete_ToDo_items() throws Throwable {
- 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 of the incomplete items$")
- public void I_choose_the_first_one() throws Throwable {
- @SuppressWarnings("unchecked")
- List<ToDoItem> notYetComplete = getVar(null, "notYetCompleteItems", List.class);
- assertThat(notYetComplete.isEmpty(), is(false));
-
- putVar("todo", "toDoItem", notYetComplete.get(0));
- }
-
- @When("^mark the item as complete$")
- public void mark_it_as_complete() throws Throwable {
- 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 {
- 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));
-
- 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();
- }
- });
- }
-
- 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));
- }
-}