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/12 15:09:03 UTC

git commit: ISIS-463: new IntegrationTestAbstract; added convenience mehods.

Updated Branches:
  refs/heads/master 33c61d43b -> 593f500bc


ISIS-463: new IntegrationTestAbstract; added convenience mehods.


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

Branch: refs/heads/master
Commit: 593f500bcde5a4083a2d664968a29b796873b791
Parents: 33c61d4
Author: Dan Haywood <da...@apache.org>
Authored: Fri Jul 12 13:59:14 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Jul 12 13:59:14 2013 +0100

----------------------------------------------------------------------
 .../IntegrationTestAbstract.java                | 148 +++++++++++++++++++
 .../integtestsupport/IsisSystemForTest.java     |  22 ++-
 .../ScenarioExecutionForIntegration.java        |  11 +-
 .../specsupport/specs/CukeStepDefsAbstract.java | 135 ++++++++++++++++-
 4 files changed, 304 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/593f500b/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
new file mode 100644
index 0000000..e4f9d55
--- /dev/null
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract.java
@@ -0,0 +1,148 @@
+/*
+ *  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.integtestsupport;
+
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.MethodRule;
+import org.junit.runners.model.FrameworkMethod;
+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.unittestsupport.jmocking.JUnitRuleMockery2;
+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 combine.  However, the code is quite simple; chosen not to in order
+ * to make it easier to see the equivalence of these two classes.
+ * 
+ */
+public abstract class IntegrationTestAbstract {
+
+    protected static ScenarioExecution scenarioExecution;
+
+    // //////////////////////////////////////
+
+    
+    /**
+     * Convenience method
+     */
+    public void put(String type, String id, Object value) {
+        scenarioExecution().put(type, id, value);
+    }
+    
+    /**
+     * Convenience method
+     */
+    public Object get(String type, String id) {
+        return scenarioExecution().get(type, id);
+    }
+
+    /**
+     * Convenience method
+     */
+    public <X> X get(String type, String id, Class<X> cls) {
+        return scenarioExecution().get(type, id ,cls);
+    }
+
+    /**
+     * 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 scenarioExecution().wrapperFactory().wrap(obj);
+    }
+
+    /**
+     * Convenience method
+     */
+    protected <T> T unwrap(T obj) {
+        return scenarioExecution().wrapperFactory().unwrap(obj);
+    }
+
+
+    private ScenarioExecution scenarioExecution() {
+        return scenarioExecution;
+    }
+    
+    // //////////////////////////////////////
+
+    /**
+     * The order is important; this rule is outermost, and must - at a minimum - come before
+     * the {@link #expectedExceptions} rule.
+     */
+    @Rule
+    public IsisTransactionRule isisTransactionRule = new IsisTransactionRule();
+
+    private static class IsisTransactionRule implements MethodRule  {
+
+        @Override
+        public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
+            final IsisSystemForTest isft = IsisSystemForTest.get(); 
+            
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    isft.beginTran();
+                    try {
+                        base.evaluate();
+                        isft.commitTran();
+                    } catch(Throwable e) {
+                        isft.bounceSystem();
+                        throw e;
+                    }
+                }
+            };
+        }
+    }
+
+    @Rule
+    public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+    @Rule
+    public ExpectedException expectedExceptions = ExpectedException.none();
+}
+

http://git-wip-us.apache.org/repos/asf/isis/blob/593f500b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
index 9f4f6d8..f054cce 100644
--- a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IsisSystemForTest.java
@@ -117,7 +117,27 @@ public class IsisSystemForTest implements org.junit.rules.TestRule, DomainServic
 
     }
 
+    // //////////////////////////////////////
 
+    private static ThreadLocal<IsisSystemForTest> ISFT = new ThreadLocal<IsisSystemForTest>();
+
+    public static IsisSystemForTest getElseNull() {
+        return ISFT.get();
+    }
+    
+    public static IsisSystemForTest get() {
+        final IsisSystemForTest isft = ISFT.get();
+        if(isft == null) {
+            throw new IllegalStateException("No IsisSystemForTest available on thread; call #set(IsisSystemForTest) first");
+        }
+        return isft;
+    }
+
+    public static void set(IsisSystemForTest isft) {
+        ISFT.set(isft);
+    }
+
+    // //////////////////////////////////////
 
 
     private IsisSystemDefault isisSystem;
@@ -673,6 +693,4 @@ public class IsisSystemForTest implements org.junit.rules.TestRule, DomainServic
     }
 
     
-    
-    
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/593f500b/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 dfc9653..7a8efde 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
@@ -18,6 +18,7 @@ package org.apache.isis.core.integtestsupport.scenarios;
 
 import org.apache.isis.applib.fixtures.InstallableFixture;
 import org.apache.isis.core.integtestsupport.IsisSystemForTest;
+import org.apache.isis.core.specsupport.scenarios.DomainServiceProvider;
 import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
 
 
@@ -33,11 +34,11 @@ import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
  */
 public class ScenarioExecutionForIntegration extends ScenarioExecution  {
 
-    protected final IsisSystemForTest isft;
-    
-    public ScenarioExecutionForIntegration(IsisSystemForTest isft) {
-        super(isft);
-        this.isft = isft;
+    private IsisSystemForTest isft;
+
+    public ScenarioExecutionForIntegration() {
+        super(IsisSystemForTest.get());
+        this.isft = (IsisSystemForTest) dsp;
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/593f500b/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 1fbad8d..190a39e 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
@@ -16,6 +16,17 @@
  */
 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.collect.Lists;
+
+import org.junit.Assert;
+
 import cucumber.api.java.Before;
 
 import org.apache.isis.applib.DomainObjectContainer;
@@ -23,8 +34,9 @@ import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
 import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
 
+
 /**
- * Base class for unit-scope Cucumber step definitions.
+ * Base class for Cucumber-JVM step definitions.
  * 
  * <p>
  * Simply declares that an instance of {@link ScenarioExecution} (or a subclass)
@@ -46,28 +58,141 @@ public abstract class CukeStepDefsAbstract {
         }
         return scenarioExecution;
     }
+
+    // //////////////////////////////////////
+
+    /**
+     * Convenience method
+     */
+    public void put(String type, String id, Object value) {
+        scenarioExecution().put(type, id, value);
+    }
     
     /**
-     * Convenience
+     * Convenience method
+     */
+    public Object get(String type, String id) {
+        return scenarioExecution().get(type, id);
+    }
+    
+    /**
+     * Convenience method
+     */
+    public <X> X get(String type, String id, Class<X> cls) {
+        return scenarioExecution().get(type, id ,cls);
+    }
+    
+    /**
+     * Convenience method
      */
     protected <T> T service(Class<T> cls) {
         return scenarioExecution().service(cls);
     }
     
     /**
-     * Convenience
+     * Convenience method
      */
     protected DomainObjectContainer container() {
         return scenarioExecution().container();
     }
     
     /**
-     * Convenience
+     * Convenience method
      */
     protected WrapperFactory wrapperFactory() {
         return scenarioExecution().wrapperFactory();
     }
     
+    /**
+     * Convenience method
+     */
+    protected <T> T wrap(T obj) {
+        return scenarioExecution.wrapperFactory().wrap(obj);
+    }
+    
+    /**
+     * Convenience method
+     */
+    protected <T> T unwrap(T obj) {
+        return scenarioExecution.wrapperFactory().unwrap(obj);
+    }
+    
+    // //////////////////////////////////////
+
+    @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()));
+
+        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);
+
+                assertThat("Values differ for property: " + propertyName, actualProp, is(expectedProp));
+            }
+        }
+    }
+
+    
+    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);
+    }
+
+
     // //////////////////////////////////////
 
     /**
@@ -94,7 +219,7 @@ public abstract class CukeStepDefsAbstract {
      *  }
      *  &#64;cucumber.api.java.Before("@integration")
      *  public void beforeScenarioIntegrationScope() {
-     *     before(new ScenarioExecutionScope(ScenarioExecutionForMyAppIntegration.class));
+     *     before(ScenarioExecutionScope.INTEGRATION);
      *  }
      * </pre>
      * where <tt>ScenarioExecutionForMyAppIntegration</tt> is an application-specific subclass of