You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/07/24 08:29:38 UTC

[isis] branch master updated: ISIS-2573: de-duplicate publishing test code (JDO/JPA)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4ea9fab  ISIS-2573: de-duplicate publishing test code (JDO/JPA)
4ea9fab is described below

commit 4ea9fab65d8923977081401d551389752ff641f6
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Jul 24 10:29:22 2021 +0200

    ISIS-2573: de-duplicate publishing test code (JDO/JPA)
---
 ...est.java => CommandPublishingTestAbstract.java} | 48 +++--------
 ...Test.java => EntityPublishingTestAbstract.java} | 41 ++--------
 ...t.java => ExecutionPublishingTestAbstract.java} | 59 +++++---------
 .../publishing/HasPersistenceStandard.java         | 42 ++++++++++
 ...st.java => PropertyPublishingTestAbstract.java} | 48 ++---------
 .../publishing/jdo/HasPersistenceStandardJdo.java  | 32 ++++++++
 .../publishing/jdo/JdoCommandPublishingTest.java   | 77 +-----------------
 .../publishing/jdo/JdoEntityPublishingTest.java    | 44 +---------
 .../publishing/jdo/JdoExecutionPublishingTest.java | 93 +---------------------
 .../publishing/jdo/JdoPropertyPublishingTest.java  | 41 +---------
 .../publishing/jpa/HasPersistenceStandardJpa.java  | 32 ++++++++
 .../publishing/jpa/JpaCommandPublishingTest.java   | 78 ++----------------
 .../publishing/jpa/JpaEntityPublishingTest.java    | 44 +---------
 .../publishing/jpa/JpaExecutionPublishingTest.java | 93 +---------------------
 .../publishing/jpa/JpaPropertyPublishingTest.java  | 41 +---------
 .../publishing/PublishingTestFactoryAbstract.java  | 16 +++-
 16 files changed, 196 insertions(+), 633 deletions(-)

diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/CommandPublishingTestAbstract.java
similarity index 67%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/CommandPublishingTestAbstract.java
index 9a3fa7d..a355f78 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/CommandPublishingTestAbstract.java
@@ -16,63 +16,34 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.publishing.jpa;
+package org.apache.isis.testdomain.publishing;
 
-import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 
 import javax.inject.Inject;
 
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.DynamicTest;
-import org.junit.jupiter.api.TestFactory;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.PropertyDto;
-import org.apache.isis.testdomain.conf.Configuration_usingJpa;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
-import org.apache.isis.testdomain.publishing.conf.Configuration_usingCommandPublishing;
 import org.apache.isis.testdomain.publishing.subscriber.CommandSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 import lombok.val;
 
-@SpringBootTest(
-        classes = {
-                Configuration_usingJpa.class,
-                Configuration_usingCommandPublishing.class,
-                PublishingTestFactoryJpa.class,
-                //XrayEnable.class
-        },
-        properties = {
-                "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG"
-        })
-@TestPropertySource({
-    IsisPresets.UseLog4j2Test
-})
-class JpaCommandPublishingTest {
-
-    @Inject private PublishingTestFactoryJpa testFactory;
-    @Inject private KVStoreForTesting kvStore;
+public abstract class CommandPublishingTestAbstract
+implements HasPersistenceStandard {
 
-    @TestFactory @DisplayName("Publishing")
-    List<DynamicTest> generateTests() {
-        return testFactory.generateTests(this::given, this::verify);
-    }
+    @Inject private KVStoreForTesting kvStore;
 
-    private void given() {
+    protected void given() {
         CommandSubscriberForTesting.clearPublishedCommands(kvStore);
     }
 
-    private void verify(final VerificationStage verificationStage) {
+    protected void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
 
         case FAILURE_CASE:
@@ -82,14 +53,15 @@ class JpaCommandPublishingTest {
 
 
 //            Interaction interaction = null;
-//            String propertyId = "org.apache.isis.testdomain.jpa.entities.JpaBook#name";
+//            String propertyId = "org.apache.isis.testdomain.jdo.entities.JdoBook#name";
 //            Object target = null;
 //            Object argValue = "Book #2";
 //            String targetMemberName = "name???";
-//            String targetClass = "org.apache.isis.testdomain.jpa.entities.JpaBook";
+//            String targetClass = "org.apache.isis.testdomain.jdo.entities.JdoBook";
 
             val propertyDto = new PropertyDto();
-            propertyDto.setLogicalMemberIdentifier("testdomain.jpa.Book#name");
+            propertyDto.setLogicalMemberIdentifier(
+                    formatPersistenceStandardSpecificLowerCase("testdomain.%s.Book#name"));
 
             val command = new Command(UUID.randomUUID());
             val commandDto = new CommandDto();
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/EntityPublishingTestAbstract.java
similarity index 63%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/EntityPublishingTestAbstract.java
index 409d1eb..9ca1af0 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/EntityPublishingTestAbstract.java
@@ -16,25 +16,13 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.publishing.jpa;
-
-import java.util.List;
+package org.apache.isis.testdomain.publishing;
 
 import javax.inject.Inject;
 
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.DynamicTest;
-import org.junit.jupiter.api.TestFactory;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.conf.Configuration_usingJpa;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
-import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityChangesPublishing;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.clearPublishedEntries;
@@ -44,35 +32,16 @@ import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubs
 import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getModified;
 import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getUpdated;
 
-@SpringBootTest(
-        classes = {
-                Configuration_usingJpa.class,
-                Configuration_usingEntityChangesPublishing.class,
-                PublishingTestFactoryJpa.class,
-                //XrayEnable.class
-        },
-        properties = {
-                "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG",
-                "logging.level.org.apache.isis.testdomain.util.kv.KVStoreForTesting=DEBUG",
-        })
-@TestPropertySource({
-    IsisPresets.UseLog4j2Test
-})
-class JpaEntityPublishingTest {
+public abstract class EntityPublishingTestAbstract
+implements HasPersistenceStandard {
 
-    @Inject private PublishingTestFactoryJpa testFactory;
     @Inject private KVStoreForTesting kvStore;
 
-    @TestFactory @DisplayName("Publishing")
-    List<DynamicTest> generateTests() {
-        return testFactory.generateTests(this::given, this::verify);
-    }
-
-    private void given() {
+    protected void given() {
         clearPublishedEntries(kvStore);
     }
 
-    private void verify(final VerificationStage verificationStage) {
+    protected void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
         case PRE_COMMIT:
         case FAILURE_CASE:
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/ExecutionPublishingTestAbstract.java
similarity index 73%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/ExecutionPublishingTestAbstract.java
index 6a94610..21b4968 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/ExecutionPublishingTestAbstract.java
@@ -16,19 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.publishing.jpa;
+package org.apache.isis.testdomain.publishing;
 
-import java.util.List;
 import java.util.Objects;
 
 import javax.inject.Inject;
 
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.DynamicTest;
-import org.junit.jupiter.api.TestFactory;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.iactn.ActionInvocation;
@@ -37,59 +30,40 @@ import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.PropertyEdit;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.conf.Configuration_usingJpa;
+import org.apache.isis.testdomain.jdo.entities.JdoBook;
 import org.apache.isis.testdomain.jpa.entities.JpaBook;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
-import org.apache.isis.testdomain.publishing.conf.Configuration_usingExecutionPublishing;
 import org.apache.isis.testdomain.publishing.subscriber.ExecutionSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 import lombok.val;
 
-@SpringBootTest(
-        classes = {
-                Configuration_usingJpa.class,
-                Configuration_usingExecutionPublishing.class,
-                PublishingTestFactoryJpa.class,
-                //XrayEnable.class
-        },
-        properties = {
-                "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG",
-        })
-@TestPropertySource({
-    IsisPresets.UseLog4j2Test
-})
-class JpaExecutionPublishingTest {
-
-    @Inject private PublishingTestFactoryJpa testFactory;
-    @Inject private KVStoreForTesting kvStore;
+public abstract class ExecutionPublishingTestAbstract
+implements HasPersistenceStandard {
 
-    @TestFactory @DisplayName("Publishing")
-    List<DynamicTest> generateTests() {
-        return testFactory.generateTests(this::given, this::verify);
-    }
+    @Inject private KVStoreForTesting kvStore;
 
-    private void given() {
+    protected void given() {
         ExecutionSubscriberForTesting.clearPublishedEntries(kvStore);
     }
 
-    private void verify(final VerificationStage verificationStage) {
+    protected void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
 
         case FAILURE_CASE:
             assertHasExecutionEntries(Can.empty());
             break;
         case POST_COMMIT:
+            val bookClass = bookClass();
             Interaction interaction = null;
             Identifier propertyId = Identifier.propertyOrCollectionIdentifier(
-                    LogicalType.fqcn(JpaBook.class), "name");
+                    LogicalType.fqcn(bookClass), "name");
             Object target = null;
             Object argValue = "Book #2";
             String targetMemberName = "name???";
-            String targetClass = "org.apache.isis.testdomain.jpa.entities.JpaBook";
+            String targetClass = bookClass.getName();
+
             assertHasExecutionEntries(Can.of(
                     new PropertyEdit(interaction, propertyId, target, argValue, targetMemberName, targetClass)
                     ));
@@ -101,6 +75,17 @@ class JpaExecutionPublishingTest {
 
     // -- HELPER
 
+    private Class<?> bookClass() {
+        switch(getPersistenceStandard()) {
+        case JDO:
+            return JdoBook.class;
+        case JPA:
+            return JpaBook.class;
+        default:
+            throw _Exceptions.unmatchedCase(getPersistenceStandard());
+        }
+    }
+
     private void assertHasExecutionEntries(final Can<Execution<?, ?>> expectedExecutions) {
         val actualExecutions = ExecutionSubscriberForTesting.getPublishedExecutions(kvStore);
         CollectionAssertions.assertComponentWiseEquals(
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/HasPersistenceStandard.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/HasPersistenceStandard.java
new file mode 100644
index 0000000..ed33f58
--- /dev/null
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/HasPersistenceStandard.java
@@ -0,0 +1,42 @@
+/*
+ *  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.testdomain.publishing;
+
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.core.metamodel.facets.object.entity.PersistenceStandard;
+
+public interface HasPersistenceStandard {
+
+    PersistenceStandard getPersistenceStandard();
+
+    default String formatPersistenceStandardSpecificLowerCase(final String format) {
+        return String.format(
+                format,
+                getPersistenceStandard().name().toLowerCase());
+    }
+
+    default String formatPersistenceStandardSpecificCapitalize(final String format) {
+        return String.format(
+                format,
+                _Strings.capitalize(getPersistenceStandard().name().toLowerCase()));
+    }
+
+
+
+}
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/PropertyPublishingTestAbstract.java
similarity index 52%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/PropertyPublishingTestAbstract.java
index 40d26f1..ee23617 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/PropertyPublishingTestAbstract.java
@@ -16,64 +16,28 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.publishing.jpa;
-
-import java.util.List;
+package org.apache.isis.testdomain.publishing;
 
 import javax.inject.Inject;
 
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.DynamicTest;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.TestFactory;
-import org.junit.jupiter.api.TestMethodOrder;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.conf.Configuration_usingJpa;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
-import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
 import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 import lombok.val;
 
-@SpringBootTest(
-        classes = {
-                Configuration_usingJpa.class,
-                Configuration_usingEntityPropertyChangePublishing.class,
-                PublishingTestFactoryJpa.class,
-                //XrayEnable.class
-        },
-        properties = {
-                "logging.level.org.springframework.orm.jpa.*=DEBUG",
-                "logging.level.org.apache.isis.applib.services.publishing.log.*=DEBUG",
-                "logging.level.org.apache.isis.testdomain.util.rest.KVStoreForTesting=DEBUG",
-                "logging.level.org.apache.isis.core.transaction.changetracking.EntityChangeTrackerDefault=DEBUG",
-        })
-@TestPropertySource({
-    IsisPresets.UseLog4j2Test
-})
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JpaPropertyPublishingTest {
+public abstract class PropertyPublishingTestAbstract
+implements HasPersistenceStandard {
 
-    @Inject private PublishingTestFactoryJpa testFactory;
     @Inject private KVStoreForTesting kvStore;
 
-    @TestFactory @DisplayName("Publishing")
-    List<DynamicTest> generateTests() {
-        return testFactory.generateTests(this::given, this::verify);
-    }
-
-    private void given() {
+    protected void given() {
         EntityPropertyChangeSubscriberForTesting.clearPropertyChangeEntries(kvStore);
     }
 
-    private void verify(final VerificationStage verificationStage) {
+    protected void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
         case PRE_COMMIT:
         case FAILURE_CASE:
@@ -82,7 +46,7 @@ class JpaPropertyPublishingTest {
         case POST_COMMIT_WHEN_PROGRAMMATIC:
         case POST_COMMIT:
             assertHasPropertyChangeEntries(Can.of(
-                    "Jpa Book/name: 'Sample Book' -> 'Book #2'"));
+                    formatPersistenceStandardSpecificCapitalize("%s Book/name: 'Sample Book' -> 'Book #2'")));
             break;
         default:
             // ignore ... no checks
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/HasPersistenceStandardJdo.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/HasPersistenceStandardJdo.java
new file mode 100644
index 0000000..0f17979
--- /dev/null
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/HasPersistenceStandardJdo.java
@@ -0,0 +1,32 @@
+/*
+ *  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.testdomain.publishing.jdo;
+
+import org.apache.isis.core.metamodel.facets.object.entity.PersistenceStandard;
+import org.apache.isis.testdomain.publishing.HasPersistenceStandard;
+
+public interface HasPersistenceStandardJdo
+extends HasPersistenceStandard {
+
+    @Override
+    default PersistenceStandard getPersistenceStandard() {
+        return PersistenceStandard.JDO;
+    }
+
+}
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java
index 58f28cb..5dd974c 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java
@@ -19,8 +19,6 @@
 package org.apache.isis.testdomain.publishing.jdo;
 
 import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
 
 import javax.inject.Inject;
 
@@ -30,20 +28,11 @@ import org.junit.jupiter.api.TestFactory;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-import org.apache.isis.schema.cmd.v2.PropertyDto;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.CommandPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJdo;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingCommandPublishing;
-import org.apache.isis.testdomain.publishing.subscriber.CommandSubscriberForTesting;
-import org.apache.isis.testdomain.util.CollectionAssertions;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import lombok.val;
 
 @SpringBootTest(
         classes = {
@@ -60,73 +49,15 @@ import lombok.val;
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JdoCommandPublishingTest {
+class JdoCommandPublishingTest
+extends CommandPublishingTestAbstract
+implements HasPersistenceStandardJdo {
 
     @Inject private PublishingTestFactoryJdo testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        CommandSubscriberForTesting.clearPublishedCommands(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-
-        case FAILURE_CASE:
-            assertHasCommandEntries(Can.empty());
-            break;
-        case POST_INTERACTION:
-
-
-//            Interaction interaction = null;
-//            String propertyId = "org.apache.isis.testdomain.jdo.entities.JdoBook#name";
-//            Object target = null;
-//            Object argValue = "Book #2";
-//            String targetMemberName = "name???";
-//            String targetClass = "org.apache.isis.testdomain.jdo.entities.JdoBook";
-
-            val propertyDto = new PropertyDto();
-            propertyDto.setLogicalMemberIdentifier("testdomain.jdo.Book#name");
-
-            val command = new Command(UUID.randomUUID());
-            val commandDto = new CommandDto();
-            commandDto.setInteractionId(command.getInteractionId().toString());
-            commandDto.setMember(propertyDto);
-
-            command.updater().setCommandDto(commandDto);
-
-            assertHasCommandEntries(Can.of(command));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
-    // -- HELPER
-
-    private void assertHasCommandEntries(final Can<Command> expectedCommands) {
-        val actualCommands = CommandSubscriberForTesting.getPublishedCommands(kvStore);
-        CollectionAssertions.assertComponentWiseEquals(
-                expectedCommands, actualCommands, this::commandDifference);
-    }
-
-    private String commandDifference(final Command a, final Command b) {
-        if(!Objects.equals(a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier())) {
-            return String.format("differing member identifier %s != %s",
-                    a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier());
-        }
-        if(!Objects.equals(a.getResult(), b.getResult())) {
-            return String.format("differing results %s != %s",
-                    a.getResult(), b.getResult());
-        }
-        return null; // no difference
-    }
-
-
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPublishingTest.java
index 4e1b0b6..08dd4af 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPublishingTest.java
@@ -28,21 +28,11 @@ import org.junit.jupiter.api.TestFactory;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.EntityPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJdo;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityChangesPublishing;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.clearPublishedEntries;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getCreated;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getDeleted;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getLoaded;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getModified;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getUpdated;
 
 @SpringBootTest(
         classes = {
@@ -60,41 +50,15 @@ import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubs
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JdoEntityPublishingTest {
+class JdoEntityPublishingTest
+extends EntityPublishingTestAbstract
+implements HasPersistenceStandardJdo {
 
     @Inject private PublishingTestFactoryJdo testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        clearPublishedEntries(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-        case PRE_COMMIT:
-        case FAILURE_CASE:
-            assertEquals(0, getCreated(kvStore));
-            assertEquals(0, getDeleted(kvStore));
-            assertEquals(0, getLoaded(kvStore));
-            assertEquals(0, getUpdated(kvStore));
-            assertEquals(0, getModified(kvStore));
-            break;
-        case POST_COMMIT_WHEN_PROGRAMMATIC:
-        case POST_COMMIT:
-            assertEquals(0, getCreated(kvStore));
-            assertEquals(0, getDeleted(kvStore));
-            //assertEquals(1, getLoaded()); // not reproducible
-            assertEquals(1, getUpdated(kvStore));
-            assertEquals(1, getModified(kvStore));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java
index f6bfbf2..454c334 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java
@@ -19,7 +19,6 @@
 package org.apache.isis.testdomain.publishing.jdo;
 
 import java.util.List;
-import java.util.Objects;
 
 import javax.inject.Inject;
 
@@ -29,25 +28,11 @@ import org.junit.jupiter.api.TestFactory;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.LogicalType;
-import org.apache.isis.applib.services.iactn.ActionInvocation;
-import org.apache.isis.applib.services.iactn.Execution;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.PropertyEdit;
-import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
-import org.apache.isis.testdomain.jdo.entities.JdoBook;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.ExecutionPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJdo;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingExecutionPublishing;
-import org.apache.isis.testdomain.publishing.subscriber.ExecutionSubscriberForTesting;
-import org.apache.isis.testdomain.util.CollectionAssertions;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import lombok.val;
 
 @SpringBootTest(
         classes = {
@@ -64,85 +49,15 @@ import lombok.val;
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JdoExecutionPublishingTest {
+class JdoExecutionPublishingTest
+extends ExecutionPublishingTestAbstract
+implements HasPersistenceStandardJdo {
 
     @Inject private PublishingTestFactoryJdo testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        ExecutionSubscriberForTesting.clearPublishedEntries(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-
-        case FAILURE_CASE:
-            assertHasExecutionEntries(Can.empty());
-            break;
-        case POST_COMMIT:
-            Interaction interaction = null;
-            Identifier propertyId = Identifier.propertyOrCollectionIdentifier(
-                    LogicalType.fqcn(JdoBook.class), "name");
-            Object target = null;
-            Object argValue = "Book #2";
-            String targetMemberName = "name???";
-            String targetClass = "org.apache.isis.testdomain.jdo.entities.JdoBook";
-            assertHasExecutionEntries(Can.of(
-                    new PropertyEdit(interaction, propertyId, target, argValue, targetMemberName, targetClass)
-                    ));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
-    // -- HELPER
-
-    private void assertHasExecutionEntries(final Can<Execution<?, ?>> expectedExecutions) {
-        val actualExecutions = ExecutionSubscriberForTesting.getPublishedExecutions(kvStore);
-        CollectionAssertions.assertComponentWiseEquals(
-                expectedExecutions, actualExecutions, this::executionDifference);
-    }
-
-    private String executionDifference(final Execution<?, ?> a, final Execution<?, ?> b) {
-        if(!Objects.equals(a.getMemberIdentifier(), b.getMemberIdentifier())) {
-            return String.format("differing member identifier %s != %s",
-                    a.getMemberIdentifier(), b.getMemberIdentifier());
-        }
-        if(!Objects.equals(a.getInteractionType(), b.getInteractionType())) {
-            return String.format("differing interaction type %s != %s",
-                    a.getInteractionType(), b.getInteractionType());
-        }
-
-        switch(a.getInteractionType()) {
-        case ACTION_INVOCATION:
-            return actionInvocationDifference(
-                    (ActionInvocation)a, (ActionInvocation)b);
-        case PROPERTY_EDIT:
-            return porpertyEditDifference(
-                    (PropertyEdit)a, (PropertyEdit)b);
-        default:
-            throw _Exceptions.unexpectedCodeReach();
-        }
-    }
-
-    private String actionInvocationDifference(final ActionInvocation a, final ActionInvocation b) {
-        return null; // no difference
-    }
-
-
-    private String porpertyEditDifference(final PropertyEdit a, final PropertyEdit b) {
-        if(!Objects.equals(a.getNewValue(), b.getNewValue())) {
-            return String.format("differing new value %s != %s",
-                    a.getNewValue(), b.getNewValue());
-        }
-
-        return null; // no difference
-    }
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoPropertyPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoPropertyPublishingTest.java
index 770e505..1307f70 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoPropertyPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoPropertyPublishingTest.java
@@ -30,17 +30,11 @@ import org.junit.jupiter.api.TestMethodOrder;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.PropertyPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJdo;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
-import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
-import org.apache.isis.testdomain.util.CollectionAssertions;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import lombok.val;
 
 @SpringBootTest(
         classes = {
@@ -59,42 +53,15 @@ import lombok.val;
     IsisPresets.UseLog4j2Test
 })
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JdoPropertyPublishingTest {
+class JdoPropertyPublishingTest
+extends PropertyPublishingTestAbstract
+implements HasPersistenceStandardJdo {
 
     @Inject private PublishingTestFactoryJdo testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        EntityPropertyChangeSubscriberForTesting.clearPropertyChangeEntries(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-        case PRE_COMMIT:
-        case FAILURE_CASE:
-            assertHasPropertyChangeEntries(Can.empty());
-            break;
-        case POST_COMMIT_WHEN_PROGRAMMATIC:
-        case POST_COMMIT:
-            assertHasPropertyChangeEntries(Can.of(
-                    "Jdo Book/name: 'Sample Book' -> 'Book #2'"));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
-    // -- HELPER
-
-    private void assertHasPropertyChangeEntries(final Can<String> expectedAuditEntries) {
-        val actualAuditEntries = EntityPropertyChangeSubscriberForTesting.getPropertyChangeEntries(kvStore);
-        CollectionAssertions.assertComponentWiseEquals(expectedAuditEntries, actualAuditEntries);
-    }
-
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/HasPersistenceStandardJpa.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/HasPersistenceStandardJpa.java
new file mode 100644
index 0000000..1183c90
--- /dev/null
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/HasPersistenceStandardJpa.java
@@ -0,0 +1,32 @@
+/*
+ *  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.testdomain.publishing.jpa;
+
+import org.apache.isis.core.metamodel.facets.object.entity.PersistenceStandard;
+import org.apache.isis.testdomain.publishing.HasPersistenceStandard;
+
+public interface HasPersistenceStandardJpa
+extends HasPersistenceStandard {
+
+    @Override
+    default PersistenceStandard getPersistenceStandard() {
+        return PersistenceStandard.JPA;
+    }
+
+}
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
index 9a3fa7d..0b14952 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
@@ -19,8 +19,6 @@
 package org.apache.isis.testdomain.publishing.jpa;
 
 import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
 
 import javax.inject.Inject;
 
@@ -30,20 +28,11 @@ import org.junit.jupiter.api.TestFactory;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-import org.apache.isis.schema.cmd.v2.PropertyDto;
 import org.apache.isis.testdomain.conf.Configuration_usingJpa;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.CommandPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingCommandPublishing;
-import org.apache.isis.testdomain.publishing.subscriber.CommandSubscriberForTesting;
-import org.apache.isis.testdomain.util.CollectionAssertions;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import lombok.val;
 
 @SpringBootTest(
         classes = {
@@ -53,78 +42,21 @@ import lombok.val;
                 //XrayEnable.class
         },
         properties = {
+                "logging.level.org.springframework.orm.jpa.*=DEBUG",
                 "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG"
         })
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JpaCommandPublishingTest {
+class JpaCommandPublishingTest
+extends CommandPublishingTestAbstract
+implements HasPersistenceStandardJpa {
 
     @Inject private PublishingTestFactoryJpa testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        CommandSubscriberForTesting.clearPublishedCommands(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-
-        case FAILURE_CASE:
-            assertHasCommandEntries(Can.empty());
-            break;
-        case POST_INTERACTION:
-
-
-//            Interaction interaction = null;
-//            String propertyId = "org.apache.isis.testdomain.jpa.entities.JpaBook#name";
-//            Object target = null;
-//            Object argValue = "Book #2";
-//            String targetMemberName = "name???";
-//            String targetClass = "org.apache.isis.testdomain.jpa.entities.JpaBook";
-
-            val propertyDto = new PropertyDto();
-            propertyDto.setLogicalMemberIdentifier("testdomain.jpa.Book#name");
-
-            val command = new Command(UUID.randomUUID());
-            val commandDto = new CommandDto();
-            commandDto.setInteractionId(command.getInteractionId().toString());
-            commandDto.setMember(propertyDto);
-
-            command.updater().setCommandDto(commandDto);
-
-            assertHasCommandEntries(Can.of(command));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
-    // -- HELPER
-
-    private void assertHasCommandEntries(final Can<Command> expectedCommands) {
-        val actualCommands = CommandSubscriberForTesting.getPublishedCommands(kvStore);
-        CollectionAssertions.assertComponentWiseEquals(
-                expectedCommands, actualCommands, this::commandDifference);
-    }
-
-    private String commandDifference(final Command a, final Command b) {
-        if(!Objects.equals(a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier())) {
-            return String.format("differing member identifier %s != %s",
-                    a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier());
-        }
-        if(!Objects.equals(a.getResult(), b.getResult())) {
-            return String.format("differing results %s != %s",
-                    a.getResult(), b.getResult());
-        }
-        return null; // no difference
-    }
-
-
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java
index 409d1eb..bb46d9f 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPublishingTest.java
@@ -28,21 +28,11 @@ import org.junit.jupiter.api.TestFactory;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJpa;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.EntityPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityChangesPublishing;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.clearPublishedEntries;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getCreated;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getDeleted;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getLoaded;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getModified;
-import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getUpdated;
 
 @SpringBootTest(
         classes = {
@@ -58,41 +48,15 @@ import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubs
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JpaEntityPublishingTest {
+class JpaEntityPublishingTest
+extends EntityPublishingTestAbstract
+implements HasPersistenceStandardJpa {
 
     @Inject private PublishingTestFactoryJpa testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        clearPublishedEntries(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-        case PRE_COMMIT:
-        case FAILURE_CASE:
-            assertEquals(0, getCreated(kvStore));
-            assertEquals(0, getDeleted(kvStore));
-            assertEquals(0, getLoaded(kvStore));
-            assertEquals(0, getUpdated(kvStore));
-            assertEquals(0, getModified(kvStore));
-            break;
-        case POST_COMMIT_WHEN_PROGRAMMATIC:
-        case POST_COMMIT:
-            assertEquals(0, getCreated(kvStore));
-            assertEquals(0, getDeleted(kvStore));
-            //assertEquals(1, getLoaded()); // not reproducible
-            assertEquals(1, getUpdated(kvStore));
-            assertEquals(1, getModified(kvStore));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
index 6a94610..461c89d 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
@@ -19,7 +19,6 @@
 package org.apache.isis.testdomain.publishing.jpa;
 
 import java.util.List;
-import java.util.Objects;
 
 import javax.inject.Inject;
 
@@ -29,25 +28,11 @@ import org.junit.jupiter.api.TestFactory;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.LogicalType;
-import org.apache.isis.applib.services.iactn.ActionInvocation;
-import org.apache.isis.applib.services.iactn.Execution;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.PropertyEdit;
-import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJpa;
-import org.apache.isis.testdomain.jpa.entities.JpaBook;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.ExecutionPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingExecutionPublishing;
-import org.apache.isis.testdomain.publishing.subscriber.ExecutionSubscriberForTesting;
-import org.apache.isis.testdomain.util.CollectionAssertions;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import lombok.val;
 
 @SpringBootTest(
         classes = {
@@ -62,85 +47,15 @@ import lombok.val;
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JpaExecutionPublishingTest {
+class JpaExecutionPublishingTest
+extends ExecutionPublishingTestAbstract
+implements HasPersistenceStandardJpa {
 
     @Inject private PublishingTestFactoryJpa testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        ExecutionSubscriberForTesting.clearPublishedEntries(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-
-        case FAILURE_CASE:
-            assertHasExecutionEntries(Can.empty());
-            break;
-        case POST_COMMIT:
-            Interaction interaction = null;
-            Identifier propertyId = Identifier.propertyOrCollectionIdentifier(
-                    LogicalType.fqcn(JpaBook.class), "name");
-            Object target = null;
-            Object argValue = "Book #2";
-            String targetMemberName = "name???";
-            String targetClass = "org.apache.isis.testdomain.jpa.entities.JpaBook";
-            assertHasExecutionEntries(Can.of(
-                    new PropertyEdit(interaction, propertyId, target, argValue, targetMemberName, targetClass)
-                    ));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
-    // -- HELPER
-
-    private void assertHasExecutionEntries(final Can<Execution<?, ?>> expectedExecutions) {
-        val actualExecutions = ExecutionSubscriberForTesting.getPublishedExecutions(kvStore);
-        CollectionAssertions.assertComponentWiseEquals(
-                expectedExecutions, actualExecutions, this::executionDifference);
-    }
-
-    private String executionDifference(final Execution<?, ?> a, final Execution<?, ?> b) {
-        if(!Objects.equals(a.getMemberIdentifier(), b.getMemberIdentifier())) {
-            return String.format("differing member identifier %s != %s",
-                    a.getMemberIdentifier(), b.getMemberIdentifier());
-        }
-        if(!Objects.equals(a.getInteractionType(), b.getInteractionType())) {
-            return String.format("differing interaction type %s != %s",
-                    a.getInteractionType(), b.getInteractionType());
-        }
-
-        switch(a.getInteractionType()) {
-        case ACTION_INVOCATION:
-            return actionInvocationDifference(
-                    (ActionInvocation)a, (ActionInvocation)b);
-        case PROPERTY_EDIT:
-            return porpertyEditDifference(
-                    (PropertyEdit)a, (PropertyEdit)b);
-        default:
-            throw _Exceptions.unexpectedCodeReach();
-        }
-    }
-
-    private String actionInvocationDifference(final ActionInvocation a, final ActionInvocation b) {
-        return null; // no difference
-    }
-
-
-    private String porpertyEditDifference(final PropertyEdit a, final PropertyEdit b) {
-        if(!Objects.equals(a.getNewValue(), b.getNewValue())) {
-            return String.format("differing new value %s != %s",
-                    a.getNewValue(), b.getNewValue());
-        }
-
-        return null; // no difference
-    }
-
 }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java
index 40d26f1..e154023 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaPropertyPublishingTest.java
@@ -30,17 +30,11 @@ import org.junit.jupiter.api.TestMethodOrder;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJpa;
-import org.apache.isis.testdomain.publishing.PublishingTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.PropertyPublishingTestAbstract;
 import org.apache.isis.testdomain.publishing.PublishingTestFactoryJpa;
 import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
-import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
-import org.apache.isis.testdomain.util.CollectionAssertions;
-import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
-
-import lombok.val;
 
 @SpringBootTest(
         classes = {
@@ -59,42 +53,15 @@ import lombok.val;
     IsisPresets.UseLog4j2Test
 })
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JpaPropertyPublishingTest {
+class JpaPropertyPublishingTest
+extends PropertyPublishingTestAbstract
+implements HasPersistenceStandardJpa {
 
     @Inject private PublishingTestFactoryJpa testFactory;
-    @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Publishing")
     List<DynamicTest> generateTests() {
         return testFactory.generateTests(this::given, this::verify);
     }
 
-    private void given() {
-        EntityPropertyChangeSubscriberForTesting.clearPropertyChangeEntries(kvStore);
-    }
-
-    private void verify(final VerificationStage verificationStage) {
-        switch(verificationStage) {
-        case PRE_COMMIT:
-        case FAILURE_CASE:
-            assertHasPropertyChangeEntries(Can.empty());
-            break;
-        case POST_COMMIT_WHEN_PROGRAMMATIC:
-        case POST_COMMIT:
-            assertHasPropertyChangeEntries(Can.of(
-                    "Jpa Book/name: 'Sample Book' -> 'Book #2'"));
-            break;
-        default:
-            // ignore ... no checks
-        }
-    }
-
-    // -- HELPER
-
-    private void assertHasPropertyChangeEntries(final Can<String> expectedAuditEntries) {
-        val actualAuditEntries = EntityPropertyChangeSubscriberForTesting.getPropertyChangeEntries(kvStore);
-        CollectionAssertions.assertComponentWiseEquals(expectedAuditEntries, actualAuditEntries);
-    }
-
-
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/PublishingTestFactoryAbstract.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/PublishingTestFactoryAbstract.java
index 51b28d8..83c7e2e 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/PublishingTestFactoryAbstract.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/PublishingTestFactoryAbstract.java
@@ -126,12 +126,17 @@ public abstract class PublishingTestFactoryAbstract {
         boolean run(PublishingTestContext context) throws Exception;
     }
 
+    /**
+     * For each test we setup a {@link PublishingTestContext test-context},
+     * which this singleton CommitListener instance will be temporarily bound
+     * to, until the end of the test's exclusive transaction.
+     */
     @Service
     public static class CommitListener {
 
         private PublishingTestContext testContext;
 
-        /** TRANSACTION END BOUNDARY (PRE) */
+        /** transaction end boundary (pre) */
         @EventListener(TransactionBeforeCompletionEvent.class)
         public void onPreCommit(final TransactionBeforeCompletionEvent event) {
             _Probe.errOut("=== TRANSACTION before completion");
@@ -141,7 +146,7 @@ public abstract class PublishingTestFactoryAbstract {
             }
         }
 
-        /** TRANSACTION END BOUNDARY (POST)*/
+        /** transaction end boundary (post) */
         @EventListener(TransactionAfterCompletionEvent.class)
         public void onPreCommit(final TransactionAfterCompletionEvent event) {
             _Probe.errOut("=== TRANSACTION after completion");
@@ -218,18 +223,25 @@ public abstract class PublishingTestFactoryAbstract {
 
     }
 
+    /** to setup the test - method is embedded in its own interaction and transaction */
     protected abstract void setupEntity(PublishingTestContext context);
 
+    /** a test - method is embedded in its own interaction and transaction */
     protected abstract boolean programmaticExecution(PublishingTestContext context);
 
+    /** a test - method is embedded in its own interaction and transaction */
     protected abstract boolean interactionApiExecution(PublishingTestContext context);
 
+    /** a test - method is embedded in its own interaction and transaction */
     protected abstract boolean wrapperSyncExecutionNoRules(PublishingTestContext context);
 
+    /** a test - method is embedded in its own interaction and transaction */
     protected abstract boolean wrapperSyncExecutionWithFailure(PublishingTestContext context);
 
+    /** a test - method is embedded in its own interaction and transaction */
     protected abstract boolean wrapperAsyncExecutionNoRules(PublishingTestContext context) throws InterruptedException, ExecutionException, TimeoutException;
 
+    /** a test - method is embedded in its own interaction and transaction */
     protected abstract boolean wrapperAsyncExecutionWithFailure(PublishingTestContext context);