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 2017/12/20 13:19:23 UTC

[isis] 01/02: ISIS-1791: tidies up ClockFixture, TickingClockFixture, updates docs.

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 8dc422c7578077fa278538163a484edf14187799
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Dec 19 16:46:51 2017 +0000

    ISIS-1791: tidies up ClockFixture, TickingClockFixture, updates docs.
    
    Also fixes simpleapp fixtures
---
 ..._ugfun_getting-started_simpleapp-archetype.adoc |   2 +
 .../guides/ugtst/_ugtst_bdd-spec-support.adoc      |   1 -
 .../guides/ugtst/_ugtst_fixture-scripts.adoc       |  18 +-
 .../_ugtst_fixture-scripts_api-and-usage.adoc      | 318 ++++++++++-----------
 .../_ugtst_fixture-scripts_clock-fixtures.adoc     |  28 ++
 .../ugtst/_ugtst_fixture-scripts_sudo-service.adoc |   6 +-
 .../images/testing/fixture-scripts/prompt.png      | Bin 52869 -> 49181 bytes
 .../testing/fixture-scripts/prototyping-menu.png   | Bin 59183 -> 58104 bytes
 .../result-list-specifying-number.png              | Bin 63100 -> 0 bytes
 .../images/testing/fixture-scripts/result-list.png | Bin 50272 -> 82117 bytes
 .../apache/isis/applib/AppManifestAbstract.java    |  10 +-
 .../applib/fixturescripts/clock/ClockFixture.java  |  92 +++---
 .../fixturescripts/clock/TickingClockFixture.java  |  26 +-
 .../application/manifest/DomainAppAppManifest.java |  12 +-
 .../manifest/DomainAppAppManifestWithFixtures.java |   7 +-
 .../services/homepage/HomePageViewModel.layout.xml |   1 +
 .../domainapp/modules/simple/SimpleModule.java     |   7 -
 .../simple/fixture/SimpleObject_persona.java       |   8 +
 .../tests/SimpleObjectMenu_IntegTest.java          |  62 +---
 .../integtests/tests/SimpleObject_IntegTest.java   |  32 +--
 20 files changed, 319 insertions(+), 311 deletions(-)

diff --git a/adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_getting-started_simpleapp-archetype.adoc b/adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_getting-started_simpleapp-archetype.adoc
index deb3cad..47a1627 100644
--- a/adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_getting-started_simpleapp-archetype.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_getting-started_simpleapp-archetype.adoc
@@ -270,6 +270,8 @@ The BDD specs and integration tests are named according to the naming convention
 
 === myapp-module-simple
 
+NOTE: this is out of date for 1.16.0-SNAPSHOT
+
 This module is where the domain object model lives, that is the business logic of the application itself.
 This typically comprises entities, domain services, mixins and view models.
 
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_bdd-spec-support.adoc b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_bdd-spec-support.adoc
index f1c308d..991dbd9 100644
--- a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_bdd-spec-support.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_bdd-spec-support.adoc
@@ -13,7 +13,6 @@ There are many BDD tools out there; Apache Isis provides an integration with lin
 
 
 include::_ugtst_bdd-spec-support_how-it-works.adoc[leveloffset=+1]
-include::_ugtst_bdd-spec-support_key-classes.adoc[leveloffset=+1]
 include::_ugtst_bdd-spec-support_writing-a-bdd-spec.adoc[leveloffset=+1]
 include::_ugtst_bdd-spec-support_maven-configuration.adoc[leveloffset=+1]
 
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts.adoc b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts.adoc
index 2acc6ee..faa37d0 100644
--- a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts.adoc
@@ -6,20 +6,27 @@
 
 
 
-When writing integration tests (and implementing the glue for BDD specs) it can be difficult to keep the "given" short; there could be a lot of prerequisite data that needs to exist before you can actually exercise your system.  Moreover, however we do set up that data, but we also want to do so in a way that is resilient to the system changing over time.
+When writing integration tests (and implementing the glue for BDD specs) it can be difficult to keep the "given" short; there could be a lot of prerequisite data that needs to exist before you can actually exercise your system.
+Moreover, however we do set up that data, but we also want to do so in a way that is resilient to the system changing over time.
 
-On a very simple system you could probably get away with using SQL to insert directly into the database, or you could use a toolkit such as link:http://dbunit.sourceforge.net/howto.html[dbunit] to upload data from flat files.  Such approaches aren't particularly maintainable though.  If in the future the domain entities (and therefore corresponding database tables) change their structure, then all of those data sets will need updating.
+On a very simple system you could probably get away with using SQL to insert directly into the database, or you could use a toolkit such as link:http://dbunit.sourceforge.net/howto.html[dbunit] to upload data from flat files.
+Such approaches aren't particularly maintainable though.
+If in the future the domain entities (and therefore corresponding database tables) change their structure, then all of those data sets will need updating.
 
-Even more significantly, there's no way to guarantee that the data that's being loaded is logically consistent with the business behaviour of the domain objects themselves.  That is, there's nothing to stop your test from putting data into the database that would be invalid if one attempted to add it through the app.
+Even more significantly, there's no way to guarantee that the data that's being loaded is logically consistent with the business behaviour of the domain objects themselves.
+That is, there's nothing to stop your test from putting data into the database that would be invalid if one attempted to add it through the app.
 
-The solution that Apache Isis provides is a small library called *_fixture scripts_*.  A fixture script is basically a wrapper for executing arbitrary work, but that work almost always invoking a business action.
+The solution that Apache Isis provides is a small library called *_fixture scripts_*.
+A fixture script is basically a command object for executing arbitrary work, where the work in question is almost always invoking one or more business actions.
+In other words, the database is populating through the functionality of the domain object model itself.
 
 [TIP]
 ====
 If you want to learn more on this topic (with live coding!), check out this https://skillsmatter.com/skillscasts/5638-to-those-whom-much-is-given-much-is-expected[presentation] given at BDD Exchange 2014.
 ====
 
-There is another benefit to Apache Isis' fixture script approach; the fixtures can be (in prototyping mode) run from your application.  This means that fixture scripts can actually help all the way through the development lifecycle:
+There is another benefit to Apache Isis' fixture script approach; the fixtures can be (in prototyping mode) run from your application.
+This means that fixture scripts can actually help all the way through the development lifecycle:
 
 * when specifying a new feature, you can write a fixture script to get the system into the "given" state, and then start exploring the required functionality with the domain expert actually _within_ the application +
 +
@@ -40,5 +47,6 @@ The following  sections explain the API and how to go about using the API.
 
 
 include::_ugtst_fixture-scripts_api-and-usage.adoc[leveloffset=+1]
+include::_ugtst_fixture-scripts_clock-fixtures.adoc[leveloffset=+1]
 include::_ugtst_fixture-scripts_sudo-service.adoc[leveloffset=+1]
 
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_api-and-usage.adoc b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_api-and-usage.adoc
index 54c795b..200a9f6 100644
--- a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_api-and-usage.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_api-and-usage.adoc
@@ -5,7 +5,7 @@
 :_imagesdir: images/
 
 
-There are two parts to using fixture scripts: the `FixtureScripts` domain service class, and the `FixtureScript` view model class:
+There are two main parts to using fixture scripts: the `FixtureScripts` domain service class, and the `FixtureScript` view model class:
 
 * The role of the `FixtureScripts` domain service is to locate all fixture scripts from the classpath and to let them be invoked, either from an integration test/BDD spec or from the UI of your Isis app.
 
@@ -16,34 +16,26 @@ Let's look at `FixtureScripts` domain service in more detail first.
 
 == `FixtureScripts`
 
-There are two ways in which you can provide a `FixtureScripts` service.
+The framework provides a default implementation of `FixtureScripts` domain service, namely the xref:../rgsvc/rgsvc.adoc#_rgsvc_testing_FixtureScriptsDefault[`FixtureScriptsDefault`] domain service.
+This is annotated to be rendered on the secondary "Prototyping" menu.
 
-The original (pre-`1.9.0`) approach is to subclass subclass `FixtureScripts` domain service, with your subclass specifying which package to search for.
-Various other settings can also be provided, and - being a custom class - you can also add in additional actions.
-A common example is to provide a "one-shot" action to recreate a standard demo set of objects.
-
-As of `1.9.0` there is an alternative design.
-Instead of subclassing `FixtureScripts` you instead implement the xref:../rgsvc/rgsvc.adoc#_rgsvc_testing_FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`] SPI.
-(As its name suggests), this provides a `FixtureScriptsSpecification` object that contains the same information as would otherwise have been in the `FixtureScripts` subclass.
-
-The actual implementation of the `FixtureScripts` service is then provided by the framework itself, namely the xref:../rgsvc/rgsvc.adoc#_rgsvc_testing_FixtureScriptsDefault[`FixtureScriptsDefault`] domain service, annotated to be rendered on the secondary "Prototyping" menu.
-This uses the `FixtureScriptsSpecificationProvider` to adjust itself accordinly.
+The behaviour of this domain menu service can be refined by providing an implementation of the optional xref:../rgsvc/rgsvc.adoc#_rgsvc_testing_FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`] SPI.
 
 For example, here's the `FixtureScriptsSpecificationProvider` service that's generated by the xref:../ugfun/ugfun.adoc#_ugfun_getting-started_simpleapp-archetype[SimpleApp archetype]:
 
 [source,java]
 ----
-@DomainService(nature = NatureOfService.DOMAIN)
-public class DomainAppFixturesProvider implements FixtureScriptsSpecificationProvider {
-    @Override
+@DomainService( nature = NatureOfService.DOMAIN )
+public class DomainAppFixtureScriptsSpecificationProvider
+                    implements FixtureScriptsSpecificationProvider {
     public FixtureScriptsSpecification getSpecification() {
         return FixtureScriptsSpecification
-                .builder(DomainAppFixturesProvider.class)                                       // <1>
-                .with(FixtureScripts.MultipleExecutionStrategy.EXECUTE)                         // <2>
-                .withRunScriptDefault(RecreateSimpleObjects.class)                              // <3>
-                .withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES)      // <4>
-                .withRecreate(RecreateSimpleObjects.class)                                      // <5>
-                .build();
+            .builder(DomainAppFixtureScriptsSpecificationProvider.class)               // <1>
+            .with(FixtureScripts.MultipleExecutionStrategy.EXECUTE)                    // <2>
+            .withRunScriptDefault(DomainAppDemo.class)                                 // <3>
+            .withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES) // <4>
+            .withRecreate(DomainAppDemo.class)                                         // <5>
+            .build();
     }
 }
 ----
@@ -54,50 +46,10 @@ public class DomainAppFixturesProvider implements FixtureScriptsSpecificationPro
 <5> if present, enables a "recreate objects and return first" action to be displayed in the UI
 
 
-The benefit of this design - decoupling the responsibilities of the superclass and the subclass - is that it ensures that there is always an instance of `FixtureScripts` available, even if the application itself doesn't provide one.
-.
-
-By way of comparison, if using the older pre-`1.9.0` approach then you would create a subclass:
-
-[source,java]
-----
-@DomainService
-@DomainServiceLayout(
-        menuBar = DomainServiceLayout.MenuBar.SECONDARY,           // <1>
-        named="Prototyping",                                       // <2>
-        menuOrder = "500"
-)
-public class DomainAppFixturesService extends FixtureScripts {     // <3>
-    public DomainAppFixturesService() {
-        super(
-            "domainapp",                                           // <4>
-            MultipleExecutionStrategy.EXECUTE);                    // <5>
-    }
-    @Override
-    public FixtureScript default0RunFixtureScript() {
-        return findFixtureScriptFor(RecreateSimpleObjects.class);  // <6>
-    }
-    @Override
-    public List<FixtureScript> choices0RunFixtureScript() {        // <7>
-        return super.choices0RunFixtureScript();
-    }
-}
-----
-<1> in the UI, render the on the right hand side (secondary) menu bar...
-<2> ... under the "Prototyping" menu
-<3> inherit from `org.apache.isis.applib.fixturescripts.FixtureScripts`
-<4> search for all fixture scripts under the "domainapp" package; in your code this would probably be "com.mycompany.myapp" or similar
-<5> if the same fixture script (class) is encountered more than once, then run anyway; more on this in xref:../ugtst/ugtst.adoc#__ugtst_fixture-scripts_api-and-usage_organizing[Organizing Fixture scripts]], below.
-<6> (optional) specify a default fixture script to run, in this case `RecreateSimpleObjects` fixture script (see below)
-<7> make all fixture scripts found available as a drop-down (by increasing the visibility of this method to `public`)
-
-This isn't quite equivalent; you would need to write additional code to support the "recreate objects and return first" action, for example.
-
-Either way, here's how the domain service looks like in the UI:
+Here's how the domain service looks like in the UI:
 
 image::{_imagesdir}testing/fixture-scripts/prototyping-menu.png[width="700px",link="{_imagesdir}testing/fixture-scripts/prototyping-menu.png"]
 
-
 and here's what the `runFixtureScript` action prompt looks like:
 
 image::{_imagesdir}testing/fixture-scripts/prompt.png[width="700px",link="{_imagesdir}testing/fixture-scripts/prompt.png"]
@@ -148,10 +100,12 @@ A fixture script is ultimately just a block of code that can be executed, so it'
 However, we strongly recommend that you use it to invoke actions on business objects, in essence to replay what a real-life user would have done.
 That way, the fixture script will remain valid even if the underlying implementation of the system changes in the future.
 
-Here's the `RecreateSimpleObjects` fixture script from the xref:../ugfun/ugfun.adoc#_ugfun_getting-started_simpleapp-archetype[SimpleApp archetype]:
+For example, here's a fixture script called `RecreateSimpleObjects`.
+(This used to be part of the xref:../ugfun/ugfun.adoc#_ugfun_getting-started_simpleapp-archetype[SimpleApp archetype], though the archetype now ships with a more sophisticated design, discussed below):
 
 [source,java]
 ----
+@lombok.Accessors(chain = true)
 public class RecreateSimpleObjects extends FixtureScript {                   // <1>
 
     public final List<String> NAMES = Collections.unmodifiableList(Arrays.asList(
@@ -160,16 +114,13 @@ public class RecreateSimpleObjects extends FixtureScript {                   //
     public RecreateSimpleObjects() {
         withDiscoverability(Discoverability.DISCOVERABLE);                   // <3>
     }
+
+    @lombok.Getter @lombok.Setter
     private Integer number;                                                  // <4>
-    public Integer getNumber() { return number; }
-    public RecreateSimpleObjects setNumber(final Integer number) {
-        this.number = number;
-        return this;
-    }
+
+    @lombok.Getter
     private final List<SimpleObject> simpleObjects = Lists.newArrayList();   // <5>
-    public List<SimpleObject> getSimpleObjects() {
-        return simpleObjects;
-    }
+
     @Override
     protected void execute(final ExecutionContext ec) {          // <6>
         // defaults
@@ -208,55 +159,10 @@ Note that although the fixture script is a view model, it's fine to simply insta
 Because this script has exposed a "number" property, it's possible to set this from within the UI.
 For example:
 
-image::{_imagesdir}testing/fixture-scripts/prompt.png[width="700px",link="{_imagesdir}testing/fixture-scripts/prompt.png"]
+image::{_imagesdir}testing/fixture-scripts/prompt-specifying-number.png[width="700px",link="{_imagesdir}testing/fixture-scripts/prompt-specifying-number.png"]
 
 When this is executed, the framework will parse the text and attempt to reflectively set the corresponding properties on the fixture result.
-So, in this case, when the fixture script is executed we actually get 6 objects created:
-
-image::{_imagesdir}testing/fixture-scripts/result-list.png[width="700px",link="{_imagesdir}testing/fixture-scripts/result-list.png"]
-
-
-
-It's commonplace for one fixture script to call another.
-In the above example this script called `SimpleObjectsTearDown` and `SimpleObjectCreate`.
-Let's take a quick look at `SimpleObjectCreate`:
-
-[source,java]
-----
-public class SimpleObjectCreate extends FixtureScript {       // <1>
-
-    private String name;                                      // <2>
-    public String getName() { return name; }
-    public SimpleObjectCreate setName(final String name) {
-        this.name = name;
-        return this;
-    }
-    private SimpleObject simpleObject;                        // <3>
-    public SimpleObject getSimpleObject() {
-        return simpleObject;
-    }
-    @Override
-    protected void execute(final ExecutionContext ec) {       // <4>
-        String name = checkParam("name", ec, String.class);   // <5>
-        this.simpleObject = wrap(simpleObjects)               // <6>
-                                .create(name);                // <7>
-        ec.addResult(this, simpleObject);                     // <8>
-    }
-    @javax.inject.Inject
-    private SimpleObjects simpleObjects;                      // <9>
-}
-----
-<1> inherit from `org.apache.isis.applib.fixturescripts.FixtureScript`, as above
-<2> input property: name of the object; this time it is required
-<3> output property: the created simple object
-<4> the mandatory execute(...) API
-<5> the `checkParam(...)` (inherited from `FixtureScript`) will check that the "name" property has been populated (using Java's Reflection API) and throw an exception if not
-<6> wrap the injected `SimpleObjects` domain service (using the xref:../rgsvc/rgsvc.adoc#_rgsvc_application-layer-api_WrapperFactory[`WrapperFactory`]) to simulate interaction through the UI...
-<7> .. and actually create the object using the "create" business action of that service
-<8> add the resulting object to the execution context; this makes the object available to access if run from the UI
-<9> inject the domain service into the fixture script
-
-
+So, in this case, when the fixture script is executed we actually get 6 objects created.
 
 
 
@@ -269,8 +175,6 @@ For example, here's an integration test from the xref:../ugfun/ugfun.adoc#_ugfun
 [source,java]
 ----
 public class SimpleObjectIntegTest extends SimpleAppIntegTest {
-    @Inject
-    FixtureScripts fixtureScripts;                      // <1>
     SimpleObject simpleObjectWrapped;
     @Before
     public void setUp() throws Exception {
@@ -283,7 +187,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
             fs.getSimpleObjects().get(0);               // <4>
         assertThat(simpleObjectPojo).isNotNull();
 
-        simpleObjectWrapped = wrap(simpleObjectPojo);   // <5>
+        simpleObjectWrapped = wrap(simpleObjectPojo);   // <4>
     }
     @Test
     public void accessible() throws Exception {
@@ -293,72 +197,162 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
         assertThat(name).isEqualTo(fs.NAMES.get(0));
     }
     ...
+    @Inject
+    FixtureScripts fixtureScripts;                      // <5>
+}
+----
+<1> instantiate the fixture script for this test, and configure
+<2> execute the fixture script
+<3> obtain the object under test from the fixture
+<4> wrap the object (to simulate being interacted with through the UI)
+<5> inject the `FixtureScripts` domain service (just like any other domain service)
+
+
+
+== "Persona" Builder Scripts (`1.16.0-SNAPSHOT`)
+
+Good integration tests are probably the best way to understand the behaviour of the domain model: better than reading the code itself.
+Such tests should clearly separating out the "given", from the "when", from the "then".
+The "given" - the initial data set - should be as minimal as possible so that the developer reading the test knows that everything being set up is essential to the functionality under test.
+
+"Persona" instances of entity classes help the developer become familiar with the data being set up.
+For example, "Steve Single" the Customer might be 21, single and no kids, whereas vs "Meghan Married-Mum" the Customer might be married 35 with 2 kids.
+Using "Steve" vs "Meghan" immediately informs the developer about the particular scenario being explored.
+
+The `PersonaWithBuilderScript` and `PersonaWithFinder` interfaces are intended to be implemented typically by "persona" enums, where each enum instance captures the essential data of some persona.
+So, going back to the previous example, we might have:
+
+[source,xml]
+----
+public enum Customer_persona
+        implements PersonaWithBuilderScript<..>, PersonaWithFinder<..> {
+
+    SteveSingle("Steve", "Single", 21, MaritalStatus.SINGLE, 0)
+    MeghanMarriedMum("Meghan", "Married-Mum", 35, MaritalStatus.MARRIED, 2);
+    ...
 }
 ----
-<1> inject the `FixtureScripts` domain service (just like any other domain service)
-<2> instantiate the fixture script for this test, and configure
-<3> execute the fixture script
-<4> obtain the object under test from the fixture
-<5> wrap the object (to simulate being interacted with through the UI)
 
+The `PersonaWithBuilderScript` interface means that this enum is able to act as a factory for a `BuilderScriptAbstract`.
+This is a specialization of `FixtureScript` that is used to actually create the entity (customer, or whatever), using the data taken out of the enum instance:
 
+[source,xml]
+----
+public interface PersonaWithBuilderScript<T, F extends BuilderScriptAbstract<T,F>>  {
+    F builder();
+}
+----
 
+The `PersonaWithFinder` interface meanwhile indicates that the enum can "lookup" its corresponding entity from the appropriate repository domain service:
 
-[[__ugtst_fixture-scripts_api-and-usage_organizing]]
-== Organizing Fixture scripts
+[source,xml]
+----
+public interface PersonaWithFinder<T> {
+    T findUsing(final ServiceRegistry2 serviceRegistry);
 
-There are lots of ways to organize fixture scripts, but we've used them as either:
+}
+----
 
-* a fairly flat style, eg as in the xref:../ugfun/ugfun.adoc#_ugfun_getting-started_simpleapp-archetype[SimpleApp archetype], also as in the http://github.com/isisaddons/isis-app-todoapp[Isis addons' todoapp];
+(As of `1.16.0-SNAPSHOT`) the xref:../ugfun/ugfun.adoc#_ugfun_getting-started_simpleapp-archetype[SimpleApp archetype] provides a sample implementation of these interfaces:
 
-* in a "composite pattern" style, eg as in the https://github.com/estatio/estatio/blob/ea20a6ce257acede50de6ce4fd2ff29713fcd689/estatioapp/fixture/src/main/java/org/estatio/fixture/invoice/InvoiceForLeaseItemTypeOfDiscountOneQuarterForOxfMiracle005.java#L66)[Estatio open source app].
+[source,java]
+----
+@lombok.AllArgsConstructor
+public enum SimpleObject_persona
+        implements PersonaWithBuilderScript<SimpleObject, SimpleObjectBuilder>,
+                   PersonaWithFinder<SimpleObject> {
+    FOO("Foo"),
+    BAR("Bar"),
+    BAZ("Baz"),
+    FRODO("Frodo"),
+    FROYO("Froyo"),
+    FIZZ("Fizz"),
+    BIP("Bip"),
+    BOP("Bop"),
+    BANG("Bang"),
+    BOO("Boo");
+
+    private final String name;
 
-These two styles are probably best illustrated with, well, some illustrations.
-Here's a fixture script in the "flat" style for setting up a customer with some orders, a number of which has been placed:
+    @Override
+    public SimpleObjectBuilder builder() {
+        return new SimpleObjectBuilder().setName(name);
+    }
 
-image::{_imagesdir}testing/fixture-scripts/flat-1.png[width="700px",link="{_imagesdir}testing/fixture-scripts/flat-1.png"]
+    @Override
+    public SimpleObject findUsing(final ServiceRegistry2 serviceRegistry) {
+        SimpleObjectRepository simpleObjectRepository =
+            serviceRegistry.lookupService(SimpleObjectRepository.class);
+        return simpleObjectRepository.findByNameExact(name);
+    }
+}
+----
 
-Notice how we have a single script that's in control of the overall process, and takes responsibility for passing data from one fixture script to the next.
+where `SimpleObjectBuilder` in turn is:
 
-Here's a similar, simpler script, from the same fictional app, to set up two customers:
+[source,java]
+----
+@lombok.Accessors(chain = true)
+public class SimpleObjectBuilder
+            extends BuilderScriptAbstract<SimpleObject, SimpleObjectBuilder> {
 
-image::{_imagesdir}testing/fixture-scripts/flat-2.png[width="500px",link="{_imagesdir}testing/fixture-scripts/flat-2.png"]
+    @lombok.Getter @lombok.Setter
+    private String name;                                    // <1>
 
-We can reuse the same fixture "customer" script, either calling it twice or (perhaps better) passing it an array of customer details to set up.
+    @Override
+    protected void execute(final ExecutionContext ec) {
+        checkParam("name", ec, String.class);               // <2>
+        object = wrap(simpleObjectMenu).create(name);
+    }
 
-With the composite style, we rely on each fixture script to set up its own prerequisites.
-Thus:
+    @lombok.Getter
+    private SimpleObject object;                            // <3>
+
+    @javax.inject.Inject
+    SimpleObjectMenu simpleObjectMenu;
+}
+----
+<1> The persona class should set this value (copied from its own state)
+<2> the inherited "checkParam" is used to ensure that a value is set
+<3> the created entity is provided as an output
 
-image::{_imagesdir}testing/fixture-scripts/composite.png[width="550px",link="{_imagesdir}testing/fixture-scripts/composite.png"]
 
-Back in the earlier section we noted the `MultipleExecutionStrategy` setting.
-We can now explain the meaning of this: the enum value of `EXECUTE` is designed for the flat style (where every fixture script will be called), whereas the enum value of `IGNORE` is designed for the composite style, and ensures that any fixture scripts visited more than once (eg TearDown) are only every executed the first time.
+This simplifies the integration tests considerably:
+
+[source,java]
+----
+public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
 
-As already noted , the app generated by the xref:../ugfun/ugfun.adoc#_ugfun_getting-started_simpleapp-archetype[SimpleApp archetype] uses the flat structure, and we feel that it's a better at separating out the "how" (how we set up some graph of domain objects into a known state, eg a customer with shipped placed orders and a newly placed order) from the "what" (what data should we actually use for the customer's name, say).
+    SimpleObject simpleObject;
 
-The composite style tends to combine these, which one could argue does not separate responsibilities well enough.
-On the other hand, one could also make an argument that the composite style is a good way to implement precanned personas, eg "Joe", the customer who has a newly placed order, from "Mary" customer who has none.
+    @Before
+    public void setUp() {
+        // given
+        simpleObject = fixtureScripts.runBuilderScript(SimpleObject_persona.FOO.builder());
+    }
 
+    @Test
+    public void accessible() {
+        // when
+        final String name = wrap(simpleObject).getName();
 
-=== Further approaches
+        // then
+        assertThat(name).isEqualTo(simpleObject.getName());
+    }
+    ...
+}
+----
 
-As of there are two other approaches.
+Put together, the persona enums provide the "what" - hard-coded values for certain key data that the developer becomes very familiar with - while the builder provides the "how-to".
 
-The first is to take advantage of a new `MultipleExecutionStrategy`, namely `EXECUTE_ONCE_BY_VALUE`.  Under this strategy the determination as to whether to run a given fixture script is by comparing the fixture script against all others that have run.
-If all fixture scripts implement value semantics, then they can effectively determine whether they need to run or not.
+Note though that the builder scripts (`BuilderScriptAbstract` implementations) are not only for use by enum personas.
+In a more complex entity there will be many potential values that need to be selected in order to create a valid instance.
+Rather than pushing this responsibility onto the caller, instead the builder script can automatically default some of these values.
 
-This strategy was introduced in order to better support the `ExcelFixture` fixture script (provided by the (non-ASF) link:http://platform.incode.org[Incode Platform^]'s excel module.
-The `ExcelFixture` takes an Excel spreadsheet and loads up each row.
-For those cases where we wish to ensure that the same spreadsheet is not loaded more than once, the `IGNORE` strategy would have required that a trivial subclass of `ExcelFixture` is created for each and every spreadsheet.
-The `EXECUTE_ONCE_BY_VALUE` on the other hand delegates the determination to the value semantics of the `ExcelFixture`, which is based on the contents of the spreadsheet.
+For example, for a customer's date of birth, this might default to a date making the customer an adult, aged between 18 and 65, say.
+For an email address or postal address, or an image, or some "lorem ipsum" text, the (non-ASF) link:http://platform.incode.org[Incode Platform^]'s fakedata module could for randomised values.
 
-[NOTE]
-====
-Note that as of `1.10.0` the `IGNORE` enum has been deprecated, replaced by `EXECUTE_ONCE_BY_CLASS`
-====
+The benefit of an intelligent builder is that it further simplifies the test.
+The developer reading the test then knows that everything that has been specified exactly is of significance.
 
-The second approach is in recognition that there is, in fact, something of a design flaw with the concept of `MultipleExecutionStrategy`: it requires that all fixture scripts being run follow the same conventions.
-There's a good argument that this shouldn't be a global "setting": the responsibility for determining whether a given fixture script should be executed should reside not in the `FixtureScripts` service but in the `FixtureScript` itself.
 
-Thus, the `FixtureScripts.ExecutionContext` exposes the `getPreviouslyExecuted()` method that allows the fixture script to check for itself which fixture scripts have already been run, and act accordingly.
-For this approach, the `MultipleExecutionStrategy` should be left as simply `EXECUTE`.
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_clock-fixtures.adoc b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_clock-fixtures.adoc
new file mode 100644
index 0000000..9ba5959
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_clock-fixtures.adoc
@@ -0,0 +1,28 @@
+[[_ugtst_fixture-scripts_clock-fixtures]]
+= Clock Fixtures (`1.16.0-SNAPSHOT`)
+:Notice: 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 ag [...]
+:_basedir: ../../
+:_imagesdir: images/
+
+
+
+The `ClockFixture` is a pre-build fixture script that simply sets the time returned by the xref:../rgsvc/rgsvc.adoc#_rgsvc_api_ClockService[`ClockService`] to a known value.
+
+For example, to set the clock to return "3 Sept 2014", use:
+
+[source,java]
+----
+executionContext.executeChild(this, ClockFixture.setTo("2014-09-03"));
+----
+
+A variety of format strings are supported; the format "YYYY-MM-DD" (as shown above) will work in every locale.
+
+The fixture script requires that a `FixtureClock` is initialized.
+This happens automatically in any non-production environment, and in particular when running integration tests.
+
+
+The `TickingClockFixture` is another, slightly more sophisticated, fixture script.
+
+
+
+It requires that a TickingFixtureClock
\ No newline at end of file
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_sudo-service.adoc b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_sudo-service.adoc
index fbc9bdd..c9b746e 100644
--- a/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_sudo-service.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugtst/_ugtst_fixture-scripts_sudo-service.adoc
@@ -6,7 +6,8 @@
 
 
 
-Sometimes in our fixture scripts we want to perform a business action running as a particular user.  This might be for the usual reason - so that our fixtures accurately reflect the reality of the system with all business constraints enforced using the `WrapperFactory` - or more straightforwardly it might be simply that the action depends on the identity of the user invoking the action.
+Sometimes in our fixture scripts we want to perform a business action running as a particular user.
+This might be for the usual reason - so that our fixtures accurately reflect the reality of the system with all business constraints enforced using the `WrapperFactory` - or more straightforwardly it might be simply that the action depends on the identity of the user invoking the action.
 
 An example of the latter case is in the (non-ASF) http://github.com/isisaddons/isis-app-todoapp[Isis addons' todoapp]'s `ToDoItem` class:
 
@@ -56,4 +57,5 @@ toDoItem = sudoService.sudo(username,
         });
 ----
 
-Behind the scenes the `SudoService` simply talks to the `DomainObjectContainer` to override the user returned by the `getUser()` API.  It is possible to override both users and roles.
+Behind the scenes the `SudoService` simply talks to the `DomainObjectContainer` to override the user returned by the `getUser()` API.
+It is possible to override both users and roles.
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prompt.png b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prompt.png
index 6c22c49..5265855 100644
Binary files a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prompt.png and b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prompt.png differ
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prototyping-menu.png b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prototyping-menu.png
index ed85463..a4d71f6 100644
Binary files a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prototyping-menu.png and b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/prototyping-menu.png differ
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list-specifying-number.png b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list-specifying-number.png
deleted file mode 100644
index 2ac7e88..0000000
Binary files a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list-specifying-number.png and /dev/null differ
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list.png b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list.png
index abe4a0e..902ee87 100644
Binary files a/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list.png and b/adocs/documentation/src/main/asciidoc/guides/ugtst/images/testing/fixture-scripts/result-list.png differ
diff --git a/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java b/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
index 8a540d1..905f8ef 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
@@ -36,7 +36,7 @@ public abstract class AppManifestAbstract implements AppManifest {
     private final List<Class<?>> modules;
     private final List<Class<?>> additionalServices;
     private final String authMechanism;
-    private final List<Class<? extends FixtureScript>> fixtures;
+    private final List<Class<? extends FixtureScript>> fixtureClasses;
     private final Map<String, String> configurationProperties;
 
     public AppManifestAbstract(final BuilderAbstract<?> builder) {
@@ -51,12 +51,12 @@ public abstract class AppManifestAbstract implements AppManifest {
         this.additionalServices = builderAdditionalServices;
 
         this.authMechanism = determineAuthMechanism(builder);
-        this.fixtures = determineFixtures(builder);
+        this.fixtureClasses = determineFixtures(builder);
 
         // note uses this.fixtures, so must come afterwards...
         this.configurationProperties = createConfigurationProperties(
                 builder.getAllPropertyResources(), builder.getAllIndividualConfigProps(),
-                this.fixtures);
+                this.fixtureClasses);
     }
 
     private String determineAuthMechanism(final ModuleOrBuilderAbstract<?> builder) {
@@ -159,7 +159,7 @@ public abstract class AppManifestAbstract implements AppManifest {
 
     @Override
     public final List<Class<? extends FixtureScript>> getFixtures() {
-        return fixtures;
+        return fixtureClasses;
     }
 
     /**
@@ -170,7 +170,7 @@ public abstract class AppManifestAbstract implements AppManifest {
      *     using {@link Builder#withFixtureScripts(Class[])} .
      * </p>
      */
-    protected void overrideFixtures(final List<Class<? extends FixtureScript>> fixtureScripts) {
+    protected void overrideFixtures(final List<Class<? extends FixtureScript>> fixtureScriptClasses) {
         // default implementation does nothing.
     }
 
diff --git a/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/ClockFixture.java b/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/ClockFixture.java
index 364778d..5862db6 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/ClockFixture.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/ClockFixture.java
@@ -26,44 +26,65 @@ import org.joda.time.format.DateTimeFormatter;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.fixtures.FixtureClock;
 import org.apache.isis.applib.fixturescripts.FixtureScript;
+import org.apache.isis.applib.fixturescripts.FixtureScriptWithExecutionStrategy;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
 
-public class ClockFixture extends FixtureScript {
+class ClockFixture extends FixtureScript implements FixtureScriptWithExecutionStrategy {
 
-    //region > factory methods, constructors
-    public static ClockFixture setTo(final String date) {
-        return new ClockFixture(date);
+    static ClockFixture setTo(final String date) {
+        return new ClockFixture().setDate(date);
     }
 
-    private LocalDateTime localDateTime;
-    private LocalDate localDate;
-
-    public ClockFixture() {
+    ClockFixture() {
         super(null, "clock");
     }
 
-    public ClockFixture(String dateStr) {
-        super(null, "clock");
-        if(!parse(dateStr)) {
-            throw new IllegalArgumentException(dateStr + " could not be parsed as a date/time or date");
-        }
+    private String date;
+
+    public String getDate() {
+        return date;
     }
-    //endregion
 
-    //region > parseAsLocalDateTime
-    private boolean parse(String dateStr) {
-        return dateStr == null ? true : parseNonNull(dateStr);
+    public ClockFixture setDate(final String date) {
+        this.date = date;
+        return this;
     }
 
-    private boolean parseNonNull(String dateStr) {
-        this.localDateTime = parseAsLocalDateTime(dateStr);
-        if(localDateTime == null) {
-            this.localDate = parseAsLocalDate(dateStr);
+    @Override
+    protected void execute(ExecutionContext ec) {
+
+        // can only be used in the context of integration tests
+        if (!(Clock.getInstance() instanceof FixtureClock)) {
+            throw new IllegalStateException("Clock has not been initialized as a FixtureClock");
+        }
+        final FixtureClock fixtureClock = (FixtureClock) FixtureClock.getInstance();
+
+        // check that some value has been set
+        checkParam("date", ec, String.class);
+
+        // process if can be parsed as a LocalDateTime
+        LocalDateTime ldt = parseAsLocalDateTime(date);
+        if (ldt != null) {
+            fixtureClock.setDate(ldt.getYear(), ldt.getMonthOfYear(), ldt.getDayOfMonth());
+            fixtureClock.setTime(ldt.getHourOfDay(), ldt.getMinuteOfHour());
+            return;
+        }
+
+        // else process if can be parsed as a LocalDate
+        LocalDate ld = parseAsLocalDate(date);
+        if (ld != null) {
+            fixtureClock.setDate(ld.getYear(), ld.getMonthOfYear(), ld.getDayOfMonth());
+            return;
         }
-        return this.localDateTime != null || this.localDate != null;
+
+        // else
+        throw new IllegalArgumentException(String.format(
+                "'%s' could not be parsed as a local date/time or local date", date));
     }
 
+    //region > parseAsLocalDateTime
     private static LocalDate parseAsLocalDate(String dateStr) {
-        for (DateTimeFormatter formatter : new DateTimeFormatter[]{
+        for (DateTimeFormatter formatter : new DateTimeFormatter[] {
                 DateTimeFormat.fullDateTime(),
                 DateTimeFormat.mediumDateTime(),
                 DateTimeFormat.shortDateTime(),
@@ -80,7 +101,7 @@ public class ClockFixture extends FixtureScript {
     }
 
     private static LocalDateTime parseAsLocalDateTime(String dateStr) {
-        for (DateTimeFormatter formatter : new DateTimeFormatter[]{
+        for (DateTimeFormatter formatter : new DateTimeFormatter[] {
                 DateTimeFormat.fullDateTime(),
                 DateTimeFormat.mediumDateTime(),
                 DateTimeFormat.shortDateTime(),
@@ -95,29 +116,10 @@ public class ClockFixture extends FixtureScript {
         }
         return null;
     }
-    //endregion
 
     @Override
-    protected void execute(ExecutionContext fixtureResults) {
-        if(!(Clock.getInstance() instanceof FixtureClock)) {
-            throw new IllegalStateException("Clock has not been initialized as a FixtureClock");
-        }
-        final FixtureClock fixtureClock = (FixtureClock) FixtureClock.getInstance();
-
-        if(localDateTime != null) {
-            fixtureClock.setDate(localDateTime.getYear(), localDateTime.getMonthOfYear(), localDateTime.getDayOfMonth());
-            fixtureClock.setTime(localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour());
-            return;
-        }
-        if(localDate != null) {
-            fixtureClock.setDate(localDate.getYear(), localDate.getMonthOfYear(), localDate.getDayOfMonth());
-            return;
-        }
+    public FixtureScripts.MultipleExecutionStrategy getMultipleExecutionStrategy() {
+        return FixtureScripts.MultipleExecutionStrategy.EXECUTE;
     }
 
-    @Override
-    public String validateRun(String parameters) {
-        return parseAsLocalDateTime(parameters) == null && parseAsLocalDate(parameters) == null
-                ? "Parameter must be parseable as a date/time or as a date" : null;
-    }
 }
diff --git a/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/TickingClockFixture.java b/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/TickingClockFixture.java
index 2440bf6..2e6e6f7 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/TickingClockFixture.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/clock/TickingClockFixture.java
@@ -26,26 +26,42 @@ import org.apache.isis.applib.fixturescripts.FixtureScriptWithExecutionStrategy;
 import org.apache.isis.applib.fixturescripts.FixtureScripts;
 
 
-public class TickingClockFixture extends FixtureScript implements FixtureScriptWithExecutionStrategy {
+public class TickingClockFixture
+        extends FixtureScript
+        implements FixtureScriptWithExecutionStrategy {
+
+    //region > date property
+    private String date;
+    public String getDate() {
+        return date;
+    }
+    public TickingClockFixture setDate(final String date) {
+        this.date = date;
+        return this;
+    }
+    //endregion
 
     @Override
-    protected void execute(ExecutionContext executionContext) {
+    protected void execute(ExecutionContext ec) {
+
+        checkParam("date", ec, String.class);
 
         final Clock instance = Clock.getInstance();
 
         if(instance instanceof TickingFixtureClock) {
             TickingFixtureClock.reinstateExisting();
-            executionContext.executeChild(this, ClockFixture.setTo("2014-05-18"));
+            ec.executeChild(this, ClockFixture.setTo(date));
             TickingFixtureClock.replaceExisting();
         }
 
         if(instance instanceof FixtureClock) {
-            executionContext.executeChild(this, ClockFixture.setTo("2014-05-18"));
+            ec.executeChild(this, ClockFixture.setTo(date));
         }
     }
 
     @Override
     public FixtureScripts.MultipleExecutionStrategy getMultipleExecutionStrategy() {
-        return FixtureScripts.MultipleExecutionStrategy.EXECUTE_ONCE_BY_CLASS;
+        return FixtureScripts.MultipleExecutionStrategy.EXECUTE;
     }
+
 }
diff --git a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifest.java b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifest.java
index 69eaacc..96cdc75 100644
--- a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifest.java
+++ b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifest.java
@@ -27,16 +27,18 @@ import domainapp.application.DomainAppApplicationModule;
  */
 public class DomainAppAppManifest extends AppManifestAbstract2 {
 
-    public DomainAppAppManifest() {
-        super(Builder
-                .forModule(new DomainAppApplicationModule())
-                .withConfigurationPropertiesFile(DomainAppAppManifest.class,
+    public static final Builder BUILDER = Builder
+            .forModule(new DomainAppApplicationModule())
+            .withConfigurationPropertiesFile(DomainAppAppManifest.class,
                     "isis.properties",
                     "authentication_shiro.properties",
                     "persistor_datanucleus.properties",
                     "viewer_restfulobjects.properties",
                     "viewer_wicket.properties")
-                .withAuthMechanism("shiro"));
+            .withAuthMechanism("shiro");
+
+    public DomainAppAppManifest() {
+        super(BUILDER);
     }
 
 }
diff --git a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifestWithFixtures.java b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifestWithFixtures.java
index 062795e..f79d3ed 100644
--- a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifestWithFixtures.java
+++ b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/DomainAppAppManifestWithFixtures.java
@@ -22,15 +22,16 @@ import java.util.List;
 
 import org.apache.isis.applib.fixturescripts.FixtureScript;
 
-import domainapp.modules.simple.fixture.SimpleObjectBuilder;
+import domainapp.modules.simple.fixture.SimpleObject_persona;
 
 /**
  * Run the app but setting up any fixtures.
  */
 public class DomainAppAppManifestWithFixtures extends DomainAppAppManifest {
 
-    @Override protected void overrideFixtures(final List<Class<? extends FixtureScript>> fixtureScripts) {
-        fixtureScripts.add(SimpleObjectBuilder.class);
+    @Override
+    protected void overrideFixtures(final List<Class<? extends FixtureScript>> fixtureScripts) {
+        fixtureScripts.add(SimpleObject_persona.PersistAll.class);
     }
 
 }
diff --git a/example/application/simpleapp/application/src/main/java/domainapp/application/services/homepage/HomePageViewModel.layout.xml b/example/application/simpleapp/application/src/main/java/domainapp/application/services/homepage/HomePageViewModel.layout.xml
index f743828..6f6aa72 100644
--- a/example/application/simpleapp/application/src/main/java/domainapp/application/services/homepage/HomePageViewModel.layout.xml
+++ b/example/application/simpleapp/application/src/main/java/domainapp/application/services/homepage/HomePageViewModel.layout.xml
@@ -27,6 +27,7 @@
                     <action id="clearHints" hidden="EVERYWHERE"/>
                     <action id="downloadLayoutXml" hidden="EVERYWHERE"/>
                     <action id="rebuildMetamodel" hidden="EVERYWHERE"/>
+                    <action id="openRestApi" hidden="EVERYWHERE"/>
                 </bs3:col>
             </bs3:row>
         </bs3:col>
diff --git a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/SimpleModule.java b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/SimpleModule.java
index e961c22..b1498a6 100644
--- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/SimpleModule.java
+++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/SimpleModule.java
@@ -29,13 +29,6 @@ import domainapp.modules.simple.fixture.SimpleObject_persona;
 public class SimpleModule extends ModuleAbstract {
 
     @Override
-    public FixtureScript getRefDataSetupFixture() {
-        // the intention of this method is to initialize ref data rather than operational/transactional data
-        // the line below demonstrates how to persist every instance of SimpleObject_persona enum easily
-        return new PersonaEnumPersistAll(SimpleObject_persona.class);
-    }
-
-    @Override
     public FixtureScript getTeardownFixture() {
         return new TeardownFixtureAbstract2() {
             @Override
diff --git a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/fixture/SimpleObject_persona.java b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/fixture/SimpleObject_persona.java
index 6786d95..35506fa 100644
--- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/fixture/SimpleObject_persona.java
+++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/fixture/SimpleObject_persona.java
@@ -21,6 +21,7 @@ package domainapp.modules.simple.fixture;
 
 import org.apache.isis.applib.fixturescripts.PersonaWithBuilderScript;
 import org.apache.isis.applib.fixturescripts.PersonaWithFinder;
+import org.apache.isis.applib.fixturescripts.setup.PersonaEnumPersistAll;
 import org.apache.isis.applib.services.registry.ServiceRegistry2;
 
 import domainapp.modules.simple.dom.impl.SimpleObject;
@@ -54,4 +55,11 @@ public enum SimpleObject_persona implements PersonaWithBuilderScript<SimpleObjec
         SimpleObjectRepository simpleObjectRepository = serviceRegistry.lookupService(SimpleObjectRepository.class);
         return simpleObjectRepository.findByNameExact(name);
     }
+
+    public static class PersistAll
+            extends PersonaEnumPersistAll<SimpleObject_persona, SimpleObject, SimpleObjectBuilder> {
+        public PersistAll() {
+            super(SimpleObject_persona.class);
+        }
+    }
 }
diff --git a/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObjectMenu_IntegTest.java b/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObjectMenu_IntegTest.java
index 8e8b030..04d3914 100644
--- a/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObjectMenu_IntegTest.java
+++ b/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObjectMenu_IntegTest.java
@@ -30,32 +30,22 @@ import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.Test;
 
-import org.apache.isis.applib.fixturescripts.FixtureScript;
-import org.apache.isis.applib.fixturescripts.FixtureScripts;
-import org.apache.isis.applib.fixturescripts.teardown.TeardownFixtureAbstract2;
-import org.apache.isis.applib.services.xactn.TransactionService;
-
-import domainapp.modules.simple.SimpleModule;
 import domainapp.modules.simple.dom.impl.SimpleObject;
 import domainapp.modules.simple.dom.impl.SimpleObjectMenu;
-import domainapp.modules.simple.fixture.SimpleObjectBuilder;
 import domainapp.modules.simple.fixture.SimpleObject_persona;
 import domainapp.modules.simple.integtests.SimpleModuleIntegTestAbstract;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SimpleObjectMenu_IntegTest extends SimpleModuleIntegTestAbstract {
 
-    @Inject
-    FixtureScripts fixtureScripts;
-    @Inject
-    TransactionService transactionService;
-    @Inject
-    SimpleObjectMenu menu;
-
     public static class ListAll extends SimpleObjectMenu_IntegTest {
 
         @Test
-        public void happyCase() throws Exception {
+        public void happyCase() {
+
+            // given
+            fixtureScripts.runFixtureScript(new SimpleObject_persona.PersistAll());
+            transactionService.nextTransaction();
 
             // when
             final List<SimpleObject> all = wrap(menu).listAll();
@@ -65,17 +55,7 @@ public class SimpleObjectMenu_IntegTest extends SimpleModuleIntegTestAbstract {
         }
 
         @Test
-        public void whenNone() throws Exception {
-
-            // given
-            FixtureScript fs = new TeardownFixtureAbstract2() {
-                @Override
-                protected void execute(ExecutionContext executionContext) {
-                    deleteFrom(SimpleObject.class);
-                }
-            };
-            fixtureScripts.runFixtureScript(fs, null);
-            transactionService.nextTransaction();
+        public void whenNone() {
 
             // when
             final List<SimpleObject> all = wrap(menu).listAll();
@@ -88,19 +68,8 @@ public class SimpleObjectMenu_IntegTest extends SimpleModuleIntegTestAbstract {
     public static class Create extends SimpleObjectMenu_IntegTest {
 
         @Test
-        public void happyCase() throws Exception {
+        public void happyCase() {
 
-            // given
-            FixtureScript fs = new TeardownFixtureAbstract2() {
-                @Override
-                protected void execute(ExecutionContext executionContext) {
-                    deleteFrom(SimpleObject.class);
-                }
-            };
-            fixtureScripts.runFixtureScript(fs, null);
-            transactionService.nextTransaction();
-
-            // when
             wrap(menu).create("Faz");
 
             // then
@@ -109,25 +78,17 @@ public class SimpleObjectMenu_IntegTest extends SimpleModuleIntegTestAbstract {
         }
 
         @Test
-        public void whenAlreadyExists() throws Exception {
+        public void whenAlreadyExists() {
 
             // given
-            FixtureScript fs = new TeardownFixtureAbstract2() {
-                @Override
-                protected void execute(ExecutionContext executionContext) {
-                    deleteFrom(SimpleObject.class);
-                }
-            };
-            fixtureScripts.runFixtureScript(fs, null);
-            transactionService.nextTransaction();
-            wrap(menu).create("Faz");
+            fixtureScripts.runBuilderScript(SimpleObject_persona.FIZZ.builder());
             transactionService.nextTransaction();
 
             // then
             expectedExceptions.expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
 
             // when
-            wrap(menu).create("Faz");
+            wrap(menu).create("Fizz");
             transactionService.nextTransaction();
         }
 
@@ -152,4 +113,7 @@ public class SimpleObjectMenu_IntegTest extends SimpleModuleIntegTestAbstract {
         }
     }
 
+    @Inject
+    SimpleObjectMenu menu;
+
 }
\ No newline at end of file
diff --git a/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java b/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java
index a974686..75c10f9 100644
--- a/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java
+++ b/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java
@@ -25,42 +25,31 @@ import javax.inject.Inject;
 import org.junit.Before;
 import org.junit.Test;
 
-import org.apache.isis.applib.fixturescripts.FixtureScripts;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.applib.services.wrapper.DisabledException;
 import org.apache.isis.applib.services.wrapper.InvalidException;
-import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.core.metamodel.services.jdosupport.Persistable_datanucleusIdLong;
 import org.apache.isis.core.metamodel.services.jdosupport.Persistable_datanucleusVersionTimestamp;
 
 import domainapp.modules.simple.dom.impl.SimpleObject;
-import domainapp.modules.simple.dom.impl.SimpleObjectMenu;
 import domainapp.modules.simple.fixture.SimpleObject_persona;
 import domainapp.modules.simple.integtests.SimpleModuleIntegTestAbstract;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
 
-    @Inject
-    FixtureScripts fixtureScripts;
-    @Inject
-    SimpleObjectMenu simpleObjectMenu;
-    @Inject
-    TransactionService transactionService;
-
     SimpleObject simpleObject;
 
     @Before
-    public void setUp() throws Exception {
-        simpleObject = SimpleObject_persona.FOO.findUsing(serviceRegistry);
-
-        assertThat(simpleObject).isNotNull();
+    public void setUp() {
+        // given
+        simpleObject = fixtureScripts.runBuilderScript(SimpleObject_persona.FOO.builder());
     }
 
     public static class Name extends SimpleObject_IntegTest {
 
         @Test
-        public void accessible() throws Exception {
+        public void accessible() {
             // when
             final String name = wrap(simpleObject).getName();
 
@@ -69,7 +58,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
         }
 
         @Test
-        public void not_editable() throws Exception {
+        public void not_editable() {
             // expect
             expectedExceptions.expect(DisabledException.class);
 
@@ -82,7 +71,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
     public static class UpdateName extends SimpleObject_IntegTest {
 
         @Test
-        public void can_be_updated_directly() throws Exception {
+        public void can_be_updated_directly() {
 
             // when
             wrap(simpleObject).updateName("new name");
@@ -93,7 +82,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
         }
 
         @Test
-        public void failsValidation() throws Exception {
+        public void failsValidation() {
 
             // expect
             expectedExceptions.expect(InvalidException.class);
@@ -111,7 +100,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
         TitleService titleService;
 
         @Test
-        public void interpolatesName() throws Exception {
+        public void interpolatesName() {
 
             // given
             final String name = wrap(simpleObject).getName();
@@ -127,7 +116,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
     public static class DataNucleusId extends SimpleObject_IntegTest {
 
         @Test
-        public void should_be_populated() throws Exception {
+        public void should_be_populated() {
             // when
             final Long id = mixin(Persistable_datanucleusIdLong.class, simpleObject).prop();
 
@@ -139,7 +128,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
     public static class DataNucleusVersionTimestamp extends SimpleObject_IntegTest {
 
         @Test
-        public void should_be_populated() throws Exception {
+        public void should_be_populated() {
             // when
             final Timestamp timestamp = mixin(Persistable_datanucleusVersionTimestamp.class, simpleObject).prop();
             // then
@@ -147,5 +136,4 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract {
         }
     }
 
-
 }
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
"commits@isis.apache.org" <co...@isis.apache.org>.