diff --git a/ragconnect.base/build.gradle b/ragconnect.base/build.gradle
index d5420c6dbf3d4b3e4860956fdda9486e5bd2ae4d..7dfe1e77b8599daad3915c6c94c0f995937f0edb 100644
--- a/ragconnect.base/build.gradle
+++ b/ragconnect.base/build.gradle
@@ -266,3 +266,9 @@ publishing {
 // --- Task order ---
 generateAst.dependsOn relast
 publish.dependsOn jar
+
+// --- Misc ---
+dependencyUpdates {
+    gradleReleaseChannel = 'current'
+    revision = 'release'
+}
diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle
index 4da4ee9ea07110aa3e91cc18a71074f19155c079..ad9cff1725069ac97ba81bf008bbdaa712f18b09 100644
--- a/ragconnect.tests/build.gradle
+++ b/ragconnect.tests/build.gradle
@@ -53,6 +53,7 @@ dependencies {
     testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.4.0'
     testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.12.1'
     testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.1.1'
+    testImplementation group: 'io.github.artsok', name: 'rerunner-jupiter', version: '2.1.6'
 
     // jackson (for serialization of types)
     implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.1'
@@ -257,12 +258,13 @@ task compileVia(type: RagConnectTest) {
     }
 }
 
-// --- Test: token-value-send ---
-task compileTokenValueSend(type: RagConnectTest) {
+// --- Test: token-value-send-manual ---
+task compileTokenValueSendManual(type: RagConnectTest) {
     ragconnect {
         outputDir = file('src/test/02-after-ragconnect/tokenValueSend')
         inputFiles = [file('src/test/01-input/tokenValueSend/Test.relast'),
-                      file('src/test/01-input/tokenValueSend/Test.connect')]
+                      file('src/test/01-input/tokenValueSend/Test.connect'),
+                      file('src/test/01-input/tokenValueSend/TestDependencies.connect')]
         rootNode = 'A'
         extraOptions = defaultRagConnectOptionsAnd()
     }
@@ -277,6 +279,27 @@ task compileTokenValueSend(type: RagConnectTest) {
     }
 }
 
+// --- Test: token-value-send-incremental ---
+task compileTokenValueSendIncremental(type: RagConnectTest) {
+    ragconnect {
+        outputDir = file('src/test/02-after-ragconnect/tokenValueSendInc')
+        inputFiles = [file('src/test/01-input/tokenValueSend/Test.relast'),
+                      file('src/test/01-input/tokenValueSend/Test.connect')]
+        rootNode = 'A'
+        extraOptions = defaultRagConnectOptionsAnd()
+    }
+    relast {
+        useJastAddNames = true
+        grammarName = 'src/test/03-after-relast/tokenValueSend/tokenValueSendInc'
+    }
+    jastadd {
+        jastAddList = 'JastAddList'
+        packageName = 'tokenValueSendInc.ast'
+        inputFiles = [file('src/test/01-input/tokenValueSend/Test.jadd')]
+        extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL
+    }
+}
+
 // --- Test: tutorial ---
 task compileTutorial(type: RagConnectTest) {
     ragconnect {
@@ -706,3 +729,8 @@ protobuf {
         artifact = 'com.google.protobuf:protoc:3.0.0'
     }
 }
+
+dependencyUpdates {
+    gradleReleaseChannel = 'current'
+    revision = 'release'
+}
diff --git a/ragconnect.tests/src/test/01-input/tokenValueSend/Test.connect b/ragconnect.tests/src/test/01-input/tokenValueSend/Test.connect
index bcc26d1fba55b6241227f8e37e93097ced82284b..f92ab8cde71d49f5f9907acfcaf6d51deab667b0 100644
--- a/ragconnect.tests/src/test/01-input/tokenValueSend/Test.connect
+++ b/ragconnect.tests/src/test/01-input/tokenValueSend/Test.connect
@@ -10,14 +10,10 @@ receive ReceiveSendAndDepend.Value using AddPrefix ;
 send ReceiveSendAndDepend.Value using AddPostfix ;
 send ReceiveSendAndDepend.OtherOutput using AddPostfix ;
 
-ReceiveSendAndDepend.OtherOutput canDependOn ReceiveSendAndDepend.Value as dependency1 ;
-
 AddPrefix maps String s to String {:
-  System.out.println("receive " + s);
   return "Pre-" + s;
 :}
 
 AddPostfix maps String s to String {:
-  System.out.println("send " + s);
   return s + "-Post";
 :}
diff --git a/ragconnect.tests/src/test/01-input/tokenValueSend/TestDependencies.connect b/ragconnect.tests/src/test/01-input/tokenValueSend/TestDependencies.connect
new file mode 100644
index 0000000000000000000000000000000000000000..02e8fcdca30c9e381714b939336ff527c349ca71
--- /dev/null
+++ b/ragconnect.tests/src/test/01-input/tokenValueSend/TestDependencies.connect
@@ -0,0 +1 @@
+ReceiveSendAndDepend.OtherOutput canDependOn ReceiveSendAndDepend.Value as dependency1 ;
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java
index 61fc420c7e984070983dbfc181feb3519f7f1aa1..31335e5482eee4a3ef8737d28694a06a2430aba3 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java
@@ -1,6 +1,7 @@
 package org.jastadd.ragconnect.tests;
 
 import defaultOnlyRead.ast.MqttHandler;
+import io.github.artsok.RepeatedIfExceptionsTest;
 import org.junit.jupiter.api.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -16,6 +17,7 @@ import java.util.concurrent.TimeUnit;
 @Tag("mqtt")
 public abstract class AbstractMqttTest extends RagConnectTest {
 
+  protected static final int TEST_REPETITIONS = 3;
   private static boolean checkDone = false;
 
   protected static MqttHandler publisher;
@@ -55,7 +57,7 @@ public abstract class AbstractMqttTest extends RagConnectTest {
   }
 
   @Tag("mqtt")
-  @Test
+  @RepeatedIfExceptionsTest(repeats = TEST_REPETITIONS)
   public final void testCommunicateSendInitialValue() throws IOException, InterruptedException {
     this.writeCurrentValue = true;
 
@@ -73,7 +75,7 @@ public abstract class AbstractMqttTest extends RagConnectTest {
   protected abstract void communicateSendInitialValue() throws IOException, InterruptedException;
 
   @Tag("mqtt")
-  @Test
+  @RepeatedIfExceptionsTest(repeats = TEST_REPETITIONS)
   public final void testCommunicateOnlyUpdatedValue() throws IOException, InterruptedException {
     this.writeCurrentValue = false;
 
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java
index 2e7e0c7d79bd7d20e938eff6257008379306bc8d..1c10bd428a8e47087e9081516a6e4e56e3eeaf77 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java
@@ -1,6 +1,7 @@
 package org.jastadd.ragconnect.tests;
 
 import attributeInc.ast.*;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Tag;
 
 import java.io.IOException;
@@ -8,11 +9,10 @@ import java.util.Objects;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
-import java.util.function.Supplier;
 
 import static java.util.function.Predicate.isEqual;
 import static org.jastadd.ragconnect.tests.TestUtils.*;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * Test case "attribute".
@@ -36,8 +36,15 @@ public class AttributeTest extends AbstractMqttTest {
   private static final String INITIAL_STRING = "initial";
   private static final String INITIAL_STRING_FOR_INT = "1";
 
+  private static final String CHECK_BASIC = "basic";
+  private static final String CHECK_SIMPLE = "simple";
+  private static final String CHECK_TRANSFORMED = "transformed";
+  private static final String CHECK_A = "a";
+  private static final String CHECK_NTA = "nta";
+
   private MqttHandler handler;
   private ReceiverData data;
+  private TestChecker checker;
 
   private Root model;
   private SenderRoot senderString;
@@ -68,6 +75,15 @@ public class AttributeTest extends AbstractMqttTest {
     data = new ReceiverData();
     assertTrue(handler.newConnection(TOPIC_WILDCARD, bytes -> data.numberOfValues += 1));
 
+    checker = new TestUtils.TestChecker();
+    checker.setActualNumberOfValues(() -> data.numberOfValues)
+            .setCheckForString(CHECK_BASIC, this::checkBasic)
+            .setCheckForString(CHECK_SIMPLE, this::checkSimple)
+            .setCheckForString(CHECK_TRANSFORMED, this::checkTransformed)
+            .setCheckForString(CHECK_A, this::checkA)
+            .setCheckForString(CHECK_NTA, this::checkNta)
+    ;
+
     // connect receive
     assertTrue(receiverRoot.connectFromBasic(mqttUri(TOPIC_BASIC)));
     assertTrue(receiverRoot.connectFromSimpleNoMapping(mqttUri(TOPIC_SIMPLE_NO_MAPPING)));
@@ -99,140 +115,139 @@ public class AttributeTest extends AbstractMqttTest {
     waitForNonNull(receiverRoot::getFromNTANoMapping);
   }
 
-  private <T> void waitForValue(T expectedValue, Callable<T> callable) {
-    if (isWriteCurrentValue()) {
-      awaitMqtt().until(callable, isEqual(expectedValue));
-    }
-  }
-
-  private <T> void waitForNonNull(Callable<T> callable) {
-    if (isWriteCurrentValue()) {
-      awaitMqtt().until(callable, Predicate.not(isEqual(null)));
-    }
-  }
-
   @Override
   protected void communicateSendInitialValue() throws IOException, InterruptedException {
     // basic, simple(2)    <-- senderString
     // transformed(2)      <-- senderInt
     // ref-type(2), nta(2) <-- senderA
-    check(9, INITIAL_STRING, INITIAL_STRING + "Post", INITIAL_STRING_FOR_INT, INITIAL_STRING, INITIAL_STRING);
-
-    senderString.setInput("test-01");
-    check(12, "test-01", "test-01Post", INITIAL_STRING_FOR_INT, INITIAL_STRING, INITIAL_STRING);
-
-    senderString.setInput("test-01");
-    check(12, "test-01", "test-01Post", INITIAL_STRING_FOR_INT, INITIAL_STRING, INITIAL_STRING);
-
-    senderInt.setInput("20");
-    check(14, "test-01", "test-01Post", "20", INITIAL_STRING, INITIAL_STRING);
-
-    senderA.setInput("test-03");
-    check(18, "test-01", "test-01Post", "20", "test-03", "test-03");
-
-    assertTrue(senderString.disconnectSimple(mqttUri(TOPIC_SIMPLE_NO_MAPPING)));
-    assertTrue(senderString.disconnectSimple(mqttUri(TOPIC_SIMPLE_WITH_MAPPING)));
-    senderString.setInput("test-04");
-    check(19, "test-04", "test-01Post", "20", "test-03", "test-03");
-
-    assertTrue(senderA.disconnectToNTA(mqttUri(TOPIC_NTA_NO_MAPPING)));
-    senderA.setInput("test-05");
-    check(22, "test-04", "test-01Post", "20", "test-05", "test-03");
+    checker.addToNumberOfValues(9)
+            .put(CHECK_BASIC, INITIAL_STRING)
+            .put(CHECK_SIMPLE, INITIAL_STRING + "Post")
+            .put(CHECK_TRANSFORMED, INITIAL_STRING_FOR_INT)
+            .put(CHECK_A, INITIAL_STRING)
+            .put(CHECK_NTA, INITIAL_STRING);
+
+    communicateBoth();
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException {
-    waitForMqtt();
     // basic, simple(2)    <-- senderString
     // transformed(2)      <-- senderInt
     // ref-type(2), nta(2) <-- senderA
-    check(0, null, null, null, null, null);
+    checker.put(CHECK_BASIC, (String) null)
+            .put(CHECK_SIMPLE, (String) null)
+            .put(CHECK_TRANSFORMED, (String) null)
+            .put(CHECK_A, (String) null)
+            .put(CHECK_NTA, (String) null);
+
+    communicateBoth();
+  }
+
+  private void communicateBoth() throws IOException {
+    checker.check();
 
     senderString.setInput("test-01");
-    check(3, "test-01", "test-01Post", null, null, null);
+    checker.addToNumberOfValues(3)
+            .put(CHECK_BASIC, "test-01")
+            .put(CHECK_SIMPLE, "test-01Post")
+            .check();
 
     senderString.setInput("test-01");
-    check(3, "test-01", "test-01Post", null, null, null);
+    checker.check();
 
     senderInt.setInput("20");
-    check(5, "test-01", "test-01Post", "20", null, null);
+    checker.addToNumberOfValues(2)
+            .put(CHECK_TRANSFORMED, "20")
+            .check();
 
     senderA.setInput("test-03");
-    check(9, "test-01", "test-01Post", "20", "test-03", "test-03");
+    checker.addToNumberOfValues(4)
+            .put(CHECK_A, "test-03")
+            .put(CHECK_NTA, "test-03")
+            .check();
 
     assertTrue(senderString.disconnectSimple(mqttUri(TOPIC_SIMPLE_NO_MAPPING)));
     assertTrue(senderString.disconnectSimple(mqttUri(TOPIC_SIMPLE_WITH_MAPPING)));
     senderString.setInput("test-04");
-    check(10, "test-04", "test-01Post", "20", "test-03", "test-03");
+    checker.incNumberOfValues()
+            .put(CHECK_BASIC, "test-04")
+            .check();
 
     assertTrue(senderA.disconnectToNTA(mqttUri(TOPIC_NTA_NO_MAPPING)));
     senderA.setInput("test-05");
-    check(13, "test-04", "test-01Post", "20", "test-05", "test-03");
+    checker.addToNumberOfValues(3)
+            .put(CHECK_A, "test-05")
+            .check();
   }
 
-  private void check(int numberOfValues, String basic, String simple, String transformed,
-                     String a, String ntaNoMapping) {
-    awaitEquals(numberOfValues, () -> data.numberOfValues, "numberOfValues");
+  private <T> void waitForValue(T expectedValue, Callable<T> callable) {
+    if (isWriteCurrentValue()) {
+      awaitMqtt().until(callable, isEqual(expectedValue));
+    }
+  }
+
+  private <T> void waitForNonNull(Callable<T> callable) {
+    if (isWriteCurrentValue()) {
+      awaitMqtt().until(callable, Predicate.not(isEqual(null)));
+    }
+  }
 
-    awaitEquals(Objects.requireNonNullElse(basic, ""),
-            receiverRoot::getFromBasic, "basic");
+  private void checkBasic(String name, String expected) {
+    Assertions.assertEquals(Objects.requireNonNullElse(expected, ""), receiverRoot.getFromBasic(), name);
+  }
 
-    if (simple != null) {
-      awaitEquals(simple,
-              receiverRoot::getFromSimpleNoMapping, "simple");
-      awaitEquals(simple + "post",
-              receiverRoot::getFromSimpleWithMapping, "simple mapped");
+  private void checkSimple(String name, String expected) {
+    if (expected != null) {
+      assertEquals(expected, receiverRoot.getFromSimpleNoMapping(), "simple");
+      assertEquals(expected + "post", receiverRoot.getFromSimpleWithMapping(), "simple mapped");
     } else {
-      awaitEquals("",
-              receiverRoot::getFromSimpleNoMapping, "simple null");
-      awaitEquals("",
-              receiverRoot::getFromSimpleWithMapping, "simple mapped null");
+      assertEquals("", receiverRoot.getFromSimpleNoMapping(), "simple null");
+      assertEquals("", receiverRoot.getFromSimpleWithMapping(), "simple mapped null");
     }
+  }
 
-    if (transformed != null) {
-      awaitEquals(Integer.parseInt(transformed),
-              receiverRoot::getFromTransformedNoMapping, "transformed");
-      awaitEquals(Integer.parseInt(transformed) + 1,
-              receiverRoot::getFromTransformedWithMapping, "transformed mapped");
+  private void checkTransformed(String name, String expected) {
+    if (expected != null) {
+      assertEquals(Integer.parseInt(expected),
+              receiverRoot.getFromTransformedNoMapping(), "transformed");
+      assertEquals(Integer.parseInt(expected) + 1,
+              receiverRoot.getFromTransformedWithMapping(), "transformed mapped");
     } else {
-      awaitEquals(0,
-              receiverRoot::getFromTransformedNoMapping, "transformed null");
-      awaitEquals(0,
-              receiverRoot::getFromTransformedWithMapping, "transformed mapped null");
+      assertEquals(0,
+              receiverRoot.getFromTransformedNoMapping(), "transformed null");
+      assertEquals(0,
+              receiverRoot.getFromTransformedWithMapping(), "transformed mapped null");
     }
 
-    if (a != null) {
-      awaitA(a, "1",
+  }
+
+  private void checkA(String name, String expected) {
+    if (expected != null) {
+      assertA(expected, "1",
               receiverRoot.getFromReferenceTypeNoMapping(), "ref-type");
-      awaitA(a + "post", "inner1",
+      assertA(expected + "post", "inner1",
               receiverRoot.getFromReferenceTypeWithMapping(), "ref-type mapped");
-      awaitA(a + "post", "inner2",
+      assertA(expected + "post", "inner2",
               receiverRoot.getFromNTAWithMapping(), "nta mapped");
     } else {
-      awaitNull(receiverRoot::getFromReferenceTypeNoMapping, "manual ref-type null");
-      awaitNull(receiverRoot::getFromReferenceTypeWithMapping, "ref-type mapped null");
-      awaitNull(receiverRoot::getFromNTAWithMapping, "nta mapped null");
+      assertNull(receiverRoot.getFromReferenceTypeNoMapping(), "manual ref-type null");
+      assertNull(receiverRoot.getFromReferenceTypeWithMapping(), "ref-type mapped null");
+      assertNull(receiverRoot.getFromNTAWithMapping(), "nta mapped null");
     }
+  }
 
-    if (ntaNoMapping != null) {
-      awaitA(ntaNoMapping, "2",
-              receiverRoot.getFromNTANoMapping(), "nta");
+  private void checkNta(String name, String expected) {
+    if (expected != null) {
+      assertA(expected, "2", receiverRoot.getFromNTANoMapping(), "nta");
     } else {
-      awaitNull(receiverRoot::getFromNTANoMapping, "nta null");
+      assertNull(receiverRoot.getFromNTANoMapping(), "nta null");
     }
   }
 
-  private void awaitNull(Supplier<A> actual, String alias) {
-    awaitMqtt().alias(alias).until(() -> actual.get() == null);
-  }
-
-  private <T> void awaitEquals(T expected, Callable<T> actual, String alias) {
-    awaitMqtt().alias(alias).until(actual, isEqual(expected));
-  }
-
-  private void awaitA(String expectedValue, String expectedInner, A actual, String message) {
-    awaitEquals(expectedValue, actual::getValue, message + " value");
-    awaitEquals(expectedInner, actual.getInner()::getInnerValue, message + " inner");
+  private void assertA(String expectedValue, String expectedInner, A actual, String message) {
+    assertEquals(expectedValue, actual.getValue(), message + " value");
+    assertEquals(expectedInner, actual.getInner().getInnerValue(), message + " inner");
   }
 
   @Override
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ContextFreeSimpleTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ContextFreeSimpleTest.java
index ee32fbf61208b93ab0934167cfb7b276099a5079..82588b72a8629d4e7943068770dc46977413f594 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ContextFreeSimpleTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ContextFreeSimpleTest.java
@@ -1,15 +1,16 @@
 package org.jastadd.ragconnect.tests;
 
 import contextFreeSimpleInc.ast.A;
+import contextFreeSimpleInc.ast.MqttHandler;
 import contextFreeSimpleInc.ast.Root;
 import contextFreeSimpleInc.ast.SerializationException;
 import org.junit.jupiter.api.Tag;
 
 import java.io.IOException;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 import static org.jastadd.ragconnect.tests.TestUtils.mqttUri;
-import static org.jastadd.ragconnect.tests.TestUtils.waitForMqtt;
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
@@ -20,14 +21,15 @@ import static org.junit.jupiter.api.Assertions.*;
 @Tag("Incremental")
 public class ContextFreeSimpleTest extends AbstractMqttTest {
 
-  private static final String TOPIC_UNNAMED = "unnamed";
-  private static final String TOPIC_SINGLE = "single";
-  private static final String TOPIC_SINGLE_ALTERNATIVE = "double";
-  private static final String TOPIC_OPT = "opt";
-  private static final String TOPIC_LIST_1 = "list1";
-  private static final String TOPIC_LIST_2 = "list2";
+  private static final String TOPIC_WILDCARD = "context-free/#";
+  private static final String TOPIC_UNNAMED = "context-free/unnamed";
+  private static final String TOPIC_SINGLE = "context-free/single";
+  private static final String TOPIC_SINGLE_ALTERNATIVE = "context-free/double";
+  private static final String TOPIC_OPT = "context-free/opt";
+  private static final String TOPIC_LIST_1 = "context-free/list1";
+  private static final String TOPIC_LIST_2 = "context-free/list2";
 
-  /** Use initially created members as values in {@link #check(String, String, String, String, String)} */
+  /** Use initially created members as values in {@link #check(String, String, A, A)} */
   private static final String INITIAL_VALUE = null;
 
   private Root model;
@@ -37,6 +39,10 @@ public class ContextFreeSimpleTest extends AbstractMqttTest {
   private A listA1;
   private A listA2;
 
+  private ReceiverData data;
+  private MqttHandler handler;
+  private TestUtils.TestChecker checker;
+
   @Override
   protected void createModel() {
     model = new Root();
@@ -51,12 +57,27 @@ public class ContextFreeSimpleTest extends AbstractMqttTest {
     model.setOptA(optA);
     model.addListA(listA1);
     model.addListA(listA2);
+
+    data = new ReceiverData();
   }
 
   @Override
   protected void setupReceiverAndConnect() throws IOException, InterruptedException {
     model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
 
+    handler = new MqttHandler().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost());
+    assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS));
+
+    handler.newConnection(TOPIC_WILDCARD, (topic, bytes) -> data.valuesSent += 1);
+
+    checker = new TestUtils.TestChecker();
+    checker.alwaysWait()
+            .setCheckForString(TOPIC_UNNAMED, (name, expected) -> this.check(name, expected, model.getA(), unnamedA))
+            .setCheckForString(TOPIC_SINGLE, (name, expected) -> this.check(name, expected, model.getSingleA(), singleA))
+            .setCheckForString(TOPIC_OPT, (name, expected) -> this.check(name, expected, model.getOptA(), optA))
+            .setCheckForString(TOPIC_LIST_1, (name, expected) -> this.check(name, expected, model.getListA(0), listA1))
+            .setCheckForString(TOPIC_LIST_2, (name, expected) -> this.check(name, expected, model.getListA(1), listA2));
+
     assertTrue(unnamedA.connect(mqttUri(TOPIC_UNNAMED)));
     assertTrue(singleA.connect(mqttUri(TOPIC_SINGLE)));
     assertTrue(singleA.connect(mqttUri(TOPIC_SINGLE_ALTERNATIVE)));
@@ -72,97 +93,82 @@ public class ContextFreeSimpleTest extends AbstractMqttTest {
 
   @Override
   protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException {
-    check(INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE);
+    checker.put(TOPIC_UNNAMED, INITIAL_VALUE)
+            .put(TOPIC_SINGLE, INITIAL_VALUE)
+            .put(TOPIC_OPT, INITIAL_VALUE)
+            .put(TOPIC_LIST_1, INITIAL_VALUE)
+            .put(TOPIC_LIST_2, INITIAL_VALUE);
+
+    checker.check();
 
     send(TOPIC_UNNAMED, "1");
-    check("1", INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE);
+    checker.put(TOPIC_UNNAMED, "1").check();
 
     send(TOPIC_SINGLE, "2");
-    check("1", "pre2", INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE);
+    checker.put(TOPIC_SINGLE, "pre2").check();
 
     send(TOPIC_SINGLE, "2.1");
-    check("1", "pre2.1", INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE);
+    checker.put(TOPIC_SINGLE, "pre2.1").check();
 
     send(TOPIC_SINGLE, "2.2");
-    check("1", "pre2.2", INITIAL_VALUE, INITIAL_VALUE, INITIAL_VALUE);
+    checker.put(TOPIC_SINGLE, "pre2.2").check();
 
     send(TOPIC_OPT, "3");
-    check("1", "pre2.2", "3post", INITIAL_VALUE, INITIAL_VALUE);
+    checker.put(TOPIC_OPT, "3post").check();
 
     send(TOPIC_LIST_1, "4");
-    check("1", "pre2.2", "3post", "4", INITIAL_VALUE);
+    checker.put(TOPIC_LIST_1, "4").check();
 
     send(TOPIC_LIST_2, "5");
-    check("1", "pre2.2", "3post", "4", "5");
+    checker.put(TOPIC_LIST_2, "5").check();
 
     send(TOPIC_SINGLE_ALTERNATIVE, "fix");
-    check("1", "prefix", "3post", "4", "5");
+    checker.put(TOPIC_SINGLE, "prefix").check();
 
     assertTrue(model.getSingleA().disconnect(mqttUri(TOPIC_SINGLE)));
     send(TOPIC_SINGLE, "6");
     // no change to previous check since disconnected
-    check("1", "prefix", "3post", "4", "5");
+    checker.check();
 
     send(TOPIC_SINGLE_ALTERNATIVE, "7");
     // alternative topic is still active
-    check("1", "pre7", "3post", "4", "5");
+    checker.put(TOPIC_SINGLE, "pre7").check();
 
     assertTrue(model.getSingleA().disconnect(mqttUri(TOPIC_SINGLE_ALTERNATIVE)));
     send(TOPIC_SINGLE_ALTERNATIVE, "8");
     // no change to previous check since alternative topic is also disconnected now
-    check("1", "pre7", "3post", "4", "5");
+    checker.check();
   }
 
-  private void send(String topic, String value) throws IOException, InterruptedException {
+  private void send(String topic, String value) throws IOException {
     A a = new A().setValue(value);
     try {
       publisher.publish(topic, TestUtils.DefaultMappings.TreeToBytes(a::serialize));
     } catch (SerializationException e) {
       throw new IOException(e);
     }
-    waitForMqtt();
   }
 
-  @SuppressWarnings("StringEquality")
-  private void check(String unnamedValue, String singleValue, String optValue, String list1Value, String list2Value) {
-    if (INITIAL_VALUE == unnamedValue) {
-      assertEquals(unnamedA, model.getA());
-    } else {
-      assertNotEquals(unnamedA, model.getA());
-      assertEquals(unnamedValue, model.getA().getValue());
-    }
-
-    if (INITIAL_VALUE == singleValue) {
-      assertEquals(singleA, model.getSingleA());
-    } else {
-      assertNotEquals(singleA, model.getSingleA());
-      assertEquals(singleValue, model.getSingleA().getValue());
-    }
-
-    if (INITIAL_VALUE == optValue) {
-      assertEquals(optA, model.getOptA());
+  private void check(String name, String expected, A actual, A expectedIfInitial) {
+    if (Objects.equals(INITIAL_VALUE, expected)) {
+      assertEquals(expectedIfInitial, actual, name);
     } else {
-      assertNotEquals(optA, model.getOptA());
-      assertEquals(optValue, model.getOptA().getValue());
+      assertNotEquals(expectedIfInitial, actual, name);
+      assertEquals(expected, actual.getValue(), name);
     }
+  }
 
-    if (INITIAL_VALUE == list1Value) {
-      assertEquals(listA1, model.getListA(0));
-    } else {
-      assertNotEquals(listA1, model.getListA(0));
-      assertEquals(list1Value, model.getListA(0).getValue());
+  @Override
+  protected void closeConnections() {
+    if (handler != null) {
+      handler.close();
     }
-
-    if (INITIAL_VALUE == list2Value) {
-      assertEquals(listA2, model.getListA(1));
-    } else {
-      assertNotEquals(listA2, model.getListA(1));
-      assertEquals(list2Value, model.getListA(1).getValue());
+    if (model != null) {
+      model.ragconnectCloseConnections();
     }
   }
 
-  @Override
-  protected void closeConnections() {
-    model.ragconnectCloseConnections();
+  static class ReceiverData {
+    int valuesSent = 0;
   }
 }
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ExampleTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ExampleTest.java
index 655adf5776c632be7f3c9e8d91efa11dc2d5eba6..143c76b59e81afc5998c87533df0cb842a9392bd 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ExampleTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ExampleTest.java
@@ -3,6 +3,7 @@ package org.jastadd.ragconnect.tests;
 import com.google.protobuf.InvalidProtocolBufferException;
 import config.Config.RobotConfig;
 import example.ast.*;
+import org.jastadd.ragconnect.tests.TestUtils.TestChecker;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import robot.RobotStateOuterClass.RobotState;
@@ -11,7 +12,9 @@ import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 import static org.jastadd.ragconnect.tests.TestUtils.mqttUri;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.jastadd.ragconnect.tests.TestUtils.waitForMqtt;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Test case "example".
@@ -29,6 +32,7 @@ public class ExampleTest extends AbstractMqttTest {
   private Link link1;
   private Link link2;
   private MqttHandler handler;
+  private TestChecker checker;
   private ReceiverData data;
 
   @BeforeEach
@@ -87,6 +91,12 @@ public class ExampleTest extends AbstractMqttTest {
 
     data = new ReceiverData();
 
+    checker = new TestChecker();
+    checker.setActualNumberOfValues(() -> data.numberOfConfigs)
+            .setCheckForObject(TOPIC_JOINT1, (name, expected) -> assertEquals(expected, link1.getCurrentPosition(), name))
+            .setCheckForObject(TOPIC_JOINT2, (name, expected) -> assertEquals(expected, link2.getCurrentPosition(), name))
+    ;
+
     handler.newConnection(TOPIC_CONFIG, bytes -> {
       data.numberOfConfigs += 1;
       try {
@@ -105,135 +115,72 @@ public class ExampleTest extends AbstractMqttTest {
   @Override
   protected void communicateSendInitialValue() throws InterruptedException {
     // joint is currently within the safety zone, so speed should be low
-    TestUtils.waitForMqtt();
-    assertEquals(0, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(0, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(1, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(1, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(1, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(1, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
-    assertEquals(robotArm.speedLow(), data.lastConfig.getSpeed(), TestUtils.DELTA);
-
-    // change position of the first joint out of the safety zone, second still in
-    sendData(TOPIC_JOINT1, 0.2f, 0.2f, 0.2f);
-
-    // still in safety zone, so no update should have been sent
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(2, 2, 2), link1.getCurrentPosition());
-    assertEquals(1, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(1, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(2, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(2, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(2, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(1, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
+    checker.incNumberOfValues()
+            .put(TOPIC_JOINT1, makePosition(0, 0, 0))
+            .put(TOPIC_JOINT2, makePosition(-1, 0, 0));
+    checkData(0, 0, 1, 1, 1, false);
     assertEquals(robotArm.speedLow(), data.lastConfig.getSpeed(), TestUtils.DELTA);
 
-    // change position of second joint also out of the safety zone, now speed must be high
-    sendData(TOPIC_JOINT2, 0.3f, 0.4f, 0.5f);
-
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(3, 4, 5), link2.getCurrentPosition());
-    assertEquals(2, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(2, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(3, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(3, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(3, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(2, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
-    assertEquals(robotArm.speedHigh(), data.lastConfig.getSpeed(), TestUtils.DELTA);
-
-    // change position of second joint, no change after mapping
-    sendData(TOPIC_JOINT2, 0.33f, 0.42f, 0.51f);
-
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(3, 4, 5), link2.getCurrentPosition());
-    assertEquals(3, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(3, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(3, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(3, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(3, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(2, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
-
-    // change position of second joint, still out of the safety zone, no update should be sent
-    sendData(TOPIC_JOINT2, 1.3f, 2.4f, 3.5f);
-
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(13, 24, 35), link2.getCurrentPosition());
-    assertEquals(4, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(4, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(4, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(4, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(4, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(2, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
+    communicateBoth(false);
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws InterruptedException {
 // no value should have been sent
-    TestUtils.waitForMqtt();
-    assertEquals(0, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(0, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(1, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(1, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(1, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(0, data.numberOfConfigs);
+    checker.put(TOPIC_JOINT1, makePosition(0, 0, 0))
+            .put(TOPIC_JOINT2, makePosition(-1, 0, 0));
+    checkData(0, 0, 1, 1, 1, true);
 
+    communicateBoth(true);
+  }
+
+  private void communicateBoth(boolean failFirstConversion) {
     // change position of the first joint out of the safety zone, second still in
     sendData(TOPIC_JOINT1, 0.2f, 0.2f, 0.2f);
 
     // still in safety zone, hence, no value should have been sent
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(2, 2, 2), link1.getCurrentPosition());
-    assertEquals(1, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(1, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(2, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(2, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(2, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(0, data.numberOfConfigs);
+    checker.put(TOPIC_JOINT1, makePosition(2, 2, 2));
+    checkData(1, 1, 2, 2, 2, failFirstConversion);
 
     // change position of second joint also out of the safety zone, now speed must be high
     sendData(TOPIC_JOINT2, 0.3f, 0.4f, 0.5f);
 
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(3, 4, 5), link2.getCurrentPosition());
-    assertEquals(2, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(2, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(3, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(3, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(3, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(1, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
+    checker.incNumberOfValues();
+    checker.put(TOPIC_JOINT2, makePosition(3, 4, 5));
+    checkData(2, 2, 3, 3, 3, false);
     assertEquals(robotArm.speedHigh(), data.lastConfig.getSpeed(), TestUtils.DELTA);
 
     // change position of second joint, no change after mapping
     sendData(TOPIC_JOINT2, 0.33f, 0.42f, 0.51f);
 
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(3, 4, 5), link2.getCurrentPosition());
-    assertEquals(3, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(3, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(3, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(3, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(3, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(1, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
+    checker.put(TOPIC_JOINT2, makePosition(3, 4, 5));
+    checkData(3, 3, 3, 3, 3, false);
 
     // change position of second joint, still out of the safety zone, no update should be sent
     sendData(TOPIC_JOINT2, 1.3f, 2.4f, 3.5f);
 
-    TestUtils.waitForMqtt();
-    assertEquals(makePosition(13, 24, 35), link2.getCurrentPosition());
-    assertEquals(4, TestCounter.INSTANCE.numberParseLinkState);
-    assertEquals(4, TestCounter.INSTANCE.numberLinkStateToIntPosition);
-    assertEquals(4, TestCounter.INSTANCE.numberInSafetyZone);
-    assertEquals(4, TestCounter.INSTANCE.numberCreateSpeedMessage);
-    assertEquals(4, TestCounter.INSTANCE.numberSerializeRobotConfig);
-    assertEquals(1, data.numberOfConfigs);
-    assertFalse(data.failedLastConversion);
+    checker.put(TOPIC_JOINT2, makePosition(13, 24, 35));
+    checkData(4, 4, 4, 4, 4, false);
+  }
+
+  private void checkData(int expectedNumberParseLinkState,
+                         int expectedNumberLinkStateToIntPosition,
+                         int expectedNumberInSafetyZone,
+                         int expectedNumberCreateSpeedMessage,
+                         int expectedNumberSerializeRobotConfig,
+                         boolean failedLastConversion) {
+    checker.check();
+    try {
+      waitForMqtt();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    }
+    assertEquals(expectedNumberParseLinkState, TestCounter.INSTANCE.numberParseLinkState);
+    assertEquals(expectedNumberLinkStateToIntPosition, TestCounter.INSTANCE.numberLinkStateToIntPosition);
+    assertEquals(expectedNumberInSafetyZone, TestCounter.INSTANCE.numberInSafetyZone);
+    assertEquals(expectedNumberCreateSpeedMessage, TestCounter.INSTANCE.numberCreateSpeedMessage);
+    assertEquals(expectedNumberSerializeRobotConfig, TestCounter.INSTANCE.numberSerializeRobotConfig);
+    assertEquals(failedLastConversion, data.failedLastConversion);
   }
 
   @Override
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ForwardingTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ForwardingTest.java
index 570c4d04742d78501f2a206aa4149d1d79d3b9f5..314ad3f1c75adcb0438267889ff358352bb8df9e 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ForwardingTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ForwardingTest.java
@@ -1,7 +1,6 @@
 package org.jastadd.ragconnect.tests;
 
 import forwardingInc.ast.*;
-import org.assertj.core.groups.Tuple;
 import org.junit.jupiter.api.Tag;
 
 import java.io.IOException;
@@ -13,7 +12,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
 import static org.jastadd.ragconnect.tests.TestUtils.*;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Test case "forwarding".
@@ -23,16 +22,17 @@ import static org.junit.jupiter.api.Assertions.*;
 @Tag("Incremental")
 public class ForwardingTest extends AbstractMqttTest {
 
-  private static final String TOPIC_A_SINGLE = "a-single";
-  private static final String TOPIC_A_MANY = "a-many";
-  private static final String TOPIC_B_SINGLE = "b-single";
-  private static final String TOPIC_C_SINGLE = "c-single";
-  private static final String TOPIC_C_MANY = "c-many";
-  private static final String TOPIC_D_SINGLE = "d-single";
+  private static final String TOPIC_WILDCARD = "forwarding/#";
+  private static final String TOPIC_A_SINGLE = "forwarding/a-single";
+  private static final String TOPIC_A_MANY = "forwarding/a-many";
+  private static final String TOPIC_B_SINGLE = "forwarding/b-single";
+  private static final String TOPIC_C_SINGLE = "forwarding/c-single";
+  private static final String TOPIC_C_MANY = "forwarding/c-many";
+  private static final String TOPIC_D_SINGLE = "forwarding/d-single";
 
   private static final Random rand = new Random();
 
-  /** Use initially created members as values in {@link #check} method */
+  /** Use initially created members as values for {@link #communicateOnlyUpdatedValue()} method */
   private static final String INITIAL_VALUE = "initial" + rand.nextInt(100);
 
   private Root model;
@@ -41,12 +41,8 @@ public class ForwardingTest extends AbstractMqttTest {
   private MqttHandler handler;
 
   private ReceiverData data;
-  private final TestUtils.ChangeObserver observer = new TestUtils.ChangeObserver();
 
-  private final Values<A> valuesA = new Values<>();
-  private final Values<B> valuesB = new Values<>();
-  private final Values<C> valuesC = new Values<>();
-  private final Values<D> valuesD = new Values<>();
+  private TestChecker checker;
 
   @Override
   protected void createModel() {
@@ -55,53 +51,29 @@ public class ForwardingTest extends AbstractMqttTest {
     senderRoot = new SenderRoot();
     model.setSenderRoot(senderRoot);
 
-    valuesA.unnamed = new A().setValue("as1");
-    valuesA.single = new A().setValue("as1");
-    valuesA.opt = new A().setValue("as1");
-    valuesA.list1 = new A().setValue("am1");
-    valuesA.list2 = new A().setValue("am2");
-
-    senderRoot.setA(valuesA.unnamed);
-    senderRoot.setSingleA(valuesA.single);
-    senderRoot.setMaybeA(valuesA.opt);
-    senderRoot.addMultipleA(valuesA.list1);
-    senderRoot.addMultipleA(valuesA.list2);
-
-    valuesB.unnamed = new B().setValue("bs1");
-    valuesB.single = new B().setValue("bs1");
-    valuesB.opt = new B().setValue("bs1");
-    valuesB.list1 = new B().setValue("bs1");
-    valuesB.list2 = new B().setValue("bs2");
-
-    senderRoot.setB(valuesB.unnamed);
-    senderRoot.setSingleB(valuesB.single);
-    senderRoot.setMaybeB(valuesB.opt);
-    senderRoot.addMultipleB(valuesB.list1);
-    senderRoot.addMultipleB(valuesB.list2);
-
-    valuesC.unnamed = new C().setValue("cs1");
-    valuesC.single = new C().setValue("cs1");
-    valuesC.opt = new C().setValue("cs1");
-    valuesC.list1 = new C().setValue("cm1");
-    valuesC.list2 = new C().setValue("cm2");
-
-    senderRoot.setC(valuesC.unnamed);
-    senderRoot.setSingleC(valuesC.single);
-    senderRoot.setMaybeC(valuesC.opt);
-    senderRoot.addMultipleC(valuesC.list1);
-    senderRoot.addMultipleC(valuesC.list2);
-
-    valuesD.unnamed = new D().setValue("ds1");
-    valuesD.single = new D().setValue("ds1");
-    valuesD.opt = new D().setValue("ds1");
-    valuesD.list1 = new D().setValue("ds1");
-    valuesD.list2 = new D().setValue("ds2");
-
-    senderRoot.setD(valuesD.unnamed);
-    senderRoot.setSingleD(valuesD.single);
-    senderRoot.setMaybeD(valuesD.opt);
-    senderRoot.addMultipleD(valuesD.list1);
-    senderRoot.addMultipleD(valuesD.list2);
+    senderRoot.setA(new A().setValue("as1"));
+    senderRoot.setSingleA(new A().setValue("as1"));
+    senderRoot.setMaybeA(new A().setValue("as1"));
+    senderRoot.addMultipleA(new A().setValue("am1"));
+    senderRoot.addMultipleA(new A().setValue("am2"));
+
+    senderRoot.setB(new B().setValue("bs1"));
+    senderRoot.setSingleB(new B().setValue("bs1"));
+    senderRoot.setMaybeB(new B().setValue("bs1"));
+    senderRoot.addMultipleB(new B().setValue("bs1"));
+    senderRoot.addMultipleB(new B().setValue("bs2"));
+
+    senderRoot.setC(new C().setValue("cs1"));
+    senderRoot.setSingleC(new C().setValue("cs1"));
+    senderRoot.setMaybeC(new C().setValue("cs1"));
+    senderRoot.addMultipleC(new C().setValue("cm1"));
+    senderRoot.addMultipleC(new C().setValue("cm2"));
+
+    senderRoot.setD(new D().setValue("ds1"));
+    senderRoot.setSingleD(new D().setValue("ds1"));
+    senderRoot.setMaybeD(new D().setValue("ds1"));
+    senderRoot.addMultipleD(new D().setValue("ds1"));
+    senderRoot.addMultipleD(new D().setValue("ds2"));
 
     receiverRoot = new ReceiverRoot();
     model.setReceiverRoot(receiverRoot);
@@ -112,64 +84,70 @@ public class ForwardingTest extends AbstractMqttTest {
     receiverRoot.setD(new D().setValue(INITIAL_VALUE));
 
     data = new ReceiverData();
-    observer.init(
-            () -> receiverRoot.getA().getValue(),
-            () -> receiverRoot.getNumManyA() > 0 ? receiverRoot.getManyA(0).getValue() : INITIAL_VALUE,
-            () -> receiverRoot.getNumManyA() > 1 ? receiverRoot.getManyA(1).getValue() : INITIAL_VALUE,
-            () -> receiverRoot.getNumManyA() > 2 ? receiverRoot.getManyA(2).getValue() : INITIAL_VALUE,
-            () -> receiverRoot.getB().getValue(),
-            () -> receiverRoot.getC().getValue(),
-            () -> receiverRoot.getNumManyC() > 0 ? receiverRoot.getManyC(0).getValue() : INITIAL_VALUE,
-            () -> receiverRoot.getNumManyC() > 1 ? receiverRoot.getManyC(1).getValue() : INITIAL_VALUE,
-            () -> receiverRoot.getNumManyC() > 2 ? receiverRoot.getManyC(2).getValue() : INITIAL_VALUE,
-            () -> receiverRoot.getD().getValue()
-    );
   }
 
   @Override
   protected void setupReceiverAndConnect() throws IOException, InterruptedException {
     model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
 
-    // connect receive
-    assertTrue(receiverRoot.connectA(mqttUri(TOPIC_A_SINGLE)));
-    assertTrue(receiverRoot.connectManyAList(mqttUri(TOPIC_A_MANY)));
-    assertTrue(receiverRoot.connectB(mqttUri(TOPIC_B_SINGLE)));
-    assertTrue(receiverRoot.connectC(mqttUri(TOPIC_C_SINGLE)));
-    assertTrue(receiverRoot.connectManyCList(mqttUri(TOPIC_C_MANY)));
-    assertTrue(receiverRoot.connectD(mqttUri(TOPIC_D_SINGLE)));
-
     handler = new MqttHandler().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost());
     assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS));
 
     handler.publish("test", Boolean.toString(isWriteCurrentValue()).getBytes(StandardCharsets.UTF_8));
 
-    handler.newConnection("#", (topic, bytes) -> {
+    handler.newConnection(TOPIC_WILDCARD, (topic, bytes) -> {
       data.valuesSent += 1;
       data.valueSentSinceLastCheck.set(true);
     });
 
+    checker = new TestChecker();
+    checker.setActualNumberOfValues(() -> data.valuesSent)
+            .setCheckForString(TOPIC_A_SINGLE,
+                    (name, expected) -> assertThat(receiverRoot.getA().getValue()).as(name).isEqualTo(expected))
+            .setCheckForTuple(TOPIC_A_MANY,
+                    (name, expected) -> assertThat(receiverRoot.getManyAList()).extracting("Value").as(name)
+                    .containsExactlyElementsOf(expected.toList()))
+            .setCheckForString(TOPIC_B_SINGLE,
+                    (name, expected) -> assertThat(receiverRoot.getB().getValue()).as(name).isEqualTo(expected))
+            .setCheckForString(TOPIC_C_SINGLE,
+                    (name, expected) -> assertThat(receiverRoot.getC().getValue()).as(name).isEqualTo(expected))
+            .setCheckForTuple(TOPIC_C_MANY,
+                    (name, expected) -> assertThat(receiverRoot.getManyCList()).extracting("Value").as(name)
+                    .containsExactlyElementsOf(expected.toList()))
+            .setCheckForString(TOPIC_D_SINGLE,
+                    (name, expected) -> assertThat(receiverRoot.getD().getValue()).as(name).isEqualTo(expected))
+    ;
+
+    // connect receive
+    assertTrue(receiverRoot.connectA(mqttUri(TOPIC_A_SINGLE)));
+    assertTrue(receiverRoot.connectManyAList(mqttUri(TOPIC_A_MANY)));
+    assertTrue(receiverRoot.connectB(mqttUri(TOPIC_B_SINGLE)));
+    assertTrue(receiverRoot.connectC(mqttUri(TOPIC_C_SINGLE)));
+    assertTrue(receiverRoot.connectManyCList(mqttUri(TOPIC_C_MANY)));
+    assertTrue(receiverRoot.connectD(mqttUri(TOPIC_D_SINGLE)));
+
     // connect send
     assertTrueAndWaitForValue(senderRoot.connectA(mqttUri(TOPIC_A_SINGLE), isWriteCurrentValue()));
     assertTrueAndWaitForValue(senderRoot.connectSingleA(mqttUri(TOPIC_A_SINGLE), isWriteCurrentValue()));
     assertTrueAndWaitForValue(senderRoot.connectMaybeA(mqttUri(TOPIC_A_SINGLE), isWriteCurrentValue()));
     assertTrueAndWaitForValue(senderRoot.connectMultipleAList(mqttUri(TOPIC_A_MANY), isWriteCurrentValue()));
 
-    assertTrueAndWaitForValue(valuesB.unnamed.connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesB.single.connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesB.opt.connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesB.list1.connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesB.list2.connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getB().connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getSingleB().connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getMaybeB().connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getMultipleB(0).connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getMultipleB(1).connect(mqttUri(TOPIC_B_SINGLE), isWriteCurrentValue()));
 
     assertTrueAndWaitForValue(senderRoot.connectC(mqttUri(TOPIC_C_SINGLE), isWriteCurrentValue()));
     assertTrueAndWaitForValue(senderRoot.connectSingleC(mqttUri(TOPIC_C_SINGLE), isWriteCurrentValue()));
     assertTrueAndWaitForValue(senderRoot.connectMaybeC(mqttUri(TOPIC_C_SINGLE), isWriteCurrentValue()));
     assertTrueAndWaitForValue(senderRoot.connectMultipleCList(mqttUri(TOPIC_C_MANY), isWriteCurrentValue()));
 
-    assertTrueAndWaitForValue(valuesD.unnamed.connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesD.single.connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesD.opt.connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesD.list1.connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
-    assertTrueAndWaitForValue(valuesD.list2.connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getD().connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getSingleD().connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getMaybeD().connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getMultipleD(0).connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
+    assertTrueAndWaitForValue(senderRoot.getMultipleD(1).connect(mqttUri(TOPIC_D_SINGLE), isWriteCurrentValue()));
   }
 
   private void assertTrueAndWaitForValue(boolean actual) {
@@ -189,145 +167,15 @@ public class ForwardingTest extends AbstractMqttTest {
     // Sink.ManyA <-- Root.MultipleA (and C)
     // Sink.B     <-- Root.B, Root.SingleB, Root.MaybeB, indexed Root.MultipleB (and D)
     // MultipleB += "-other", all C = "pre-" + value, almost all D += "-post", MultipleD += "-other"
-
-    observer.start();
-
-    // last sent value is always list2
-    check(18, "as1", tuple("am1", "am2"), "bs2-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other", false);
-
-    // --- A ---
-    senderRoot.getA().setValue("test-3");
-    check(19, "test-3", tuple("am1", "am2"), "bs2-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getSingleA().setValue("test-4");
-    check(20, "test-4", tuple("am1", "am2"), "bs2-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getMaybeA().setValue("test-5");
-    check(21, "test-5", tuple("am1", "am2"), "bs2-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getMultipleA(0).setValue("test-6");
-    check(22, "test-5", tuple("test-6", "am2"), "bs2-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.addMultipleA(new A().setValue("test-7"));
-    check(23, "test-5", tuple("test-6", "am2", "test-7"), "bs2-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    // --- B ---
-    senderRoot.getB().setValue("test-8");
-    check(24, "test-5", tuple("test-6", "am2", "test-7"), "test-8",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getSingleB().setValue("test-9");
-    check(25, "test-5", tuple("test-6", "am2", "test-7"), "test-9",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getMaybeB().setValue("test-10");
-    check(26, "test-5", tuple("test-6", "am2", "test-7"), "test-10",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getMultipleB(0).setValue("test-11");
-    check(27, "test-5", tuple("test-6", "am2", "test-7"), "test-11-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    // not connected, so no value is sent (manually wait)
-    senderRoot.addMultipleB(new B().setValue("test-12"));
-    waitForMqtt();
-    check(27, "test-5", tuple("test-6", "am2", "test-7"), "test-11-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other", false);
-
-    assertTrue(senderRoot.getMultipleB(2).connect(mqttUri(TOPIC_B_SINGLE), true));
-    check(28, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-cs1", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    // --- C ---
-    senderRoot.getC().setValue("test-13");
-    check(29, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-13", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getSingleC().setValue("test-14");
-    check(30, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-14", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getMaybeC().setValue("test-15");
-    check(31, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-cm2"), "ds2-other");
-
-    senderRoot.getMultipleC(1).setValue("test-16");
-    check(32, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16"), "ds2-other");
-
-    senderRoot.addMultipleC(new C().setValue("test-17"));
-    check(33, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "ds2-other");
-
-    // --- D ---
-    senderRoot.getD().setValue("test-18");
-    check(34, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-18-post");
-
-    senderRoot.getSingleD().setValue("test-19");
-    check(35, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-19-post");
-
-    senderRoot.getMaybeD().setValue("test-20");
-    check(36, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-20-post");
-
-    senderRoot.getMultipleD(0).setValue("test-21");
-    check(37, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-21-other");
-
-    // not connected, so no value is sent (manually wait)
-    senderRoot.addMultipleD(new D().setValue("test-22"));
-    waitForMqtt();
-    check(37, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-21-other", false);
-
-    assertTrue(senderRoot.getMultipleD(2).connect(mqttUri(TOPIC_D_SINGLE), true));
-    check(38, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-22-other");
-
-    senderRoot.getMultipleD(2).setValue("test-23");
-    check(39, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-23-other");
-
-    // disconnecting elements, changing values must not send any message (thus not change anything on the receiver)
-    assertTrue(senderRoot.getMultipleB(1).disconnectSend(mqttUri(TOPIC_B_SINGLE)));
-    senderRoot.getMultipleB(1).setValue("test-23-ignored");
-
-    // disconnect affects complete list
-    senderRoot.getMultipleB(0).setValue("test-24-ignored");
-    senderRoot.getMultipleB(2).setValue("test-25-ignored");
-
-    assertTrue(senderRoot.getMaybeB().disconnectSend(mqttUri(TOPIC_B_SINGLE)));
-    senderRoot.getMaybeB().setValue("test-26-ignored");
-
-    assertTrue(senderRoot.getB().disconnectSend(mqttUri(TOPIC_B_SINGLE)));
-    senderRoot.getB().setValue("test-27-ignored");
-
-    waitForMqtt();
-    check(39, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-23-other", false);
-
-    // same for A
-    assertTrue(senderRoot.disconnectMultipleAList(mqttUri(TOPIC_A_MANY)));
-    senderRoot.getMultipleA(0).setValue("test-28-ignored");
-    senderRoot.getMultipleA(2).setValue("test-29-ignored");
-
-    assertTrue(senderRoot.disconnectMaybeA(mqttUri(TOPIC_A_SINGLE)));
-    senderRoot.getMaybeA().setValue("test-30-ignored");
-
-    assertTrue(senderRoot.disconnectA(mqttUri(TOPIC_A_SINGLE)));
-    senderRoot.getA().setValue("test-31-ignored");
-
-    waitForMqtt();
-    check(39, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-23-other", false);
+    checker.addToNumberOfValues(18)
+            .put(TOPIC_A_SINGLE, "as1")
+            .put(TOPIC_A_MANY, tuple("am1", "am2"))
+            .put(TOPIC_B_SINGLE, "bs2-other")
+            .put(TOPIC_C_SINGLE, "pre-cs1")
+            .put(TOPIC_C_MANY, tuple("pre-cm1", "pre-cm2"))
+            .put(TOPIC_D_SINGLE, "ds2-other");
+
+    communicateBoth();
   }
 
   @Override
@@ -337,118 +185,99 @@ public class ForwardingTest extends AbstractMqttTest {
     // Sink.B     <-- Root.B, Root.SingleB, Root.MaybeB, indexed Root.MultipleB (and D)
     // MultipleB += "-other", all C = "pre-" + value, almost all D += "-post", MultipleD += "-other"
 
-    observer.start();
-    check(0, INITIAL_VALUE, tuple(), INITIAL_VALUE,
-            INITIAL_VALUE, tuple(), INITIAL_VALUE, false);
+    checker.put(TOPIC_A_SINGLE, INITIAL_VALUE)
+            .put(TOPIC_A_MANY, tuple())
+            .put(TOPIC_B_SINGLE, INITIAL_VALUE)
+            .put(TOPIC_C_SINGLE, INITIAL_VALUE)
+            .put(TOPIC_C_MANY, tuple())
+            .put(TOPIC_D_SINGLE, INITIAL_VALUE);
+
+    communicateBoth();
+  }
+
+  private void communicateBoth() throws IOException {
+    checker.check();
 
     // --- A ---
     senderRoot.getA().setValue("test-3");
-    check(1, "test-3", tuple(), INITIAL_VALUE,
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_A_SINGLE, "test-3").check();
 
     senderRoot.getSingleA().setValue("test-4");
-    check(2, "test-4", tuple(), INITIAL_VALUE,
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_A_SINGLE, "test-4").check();
 
     senderRoot.getMaybeA().setValue("test-5");
-    check(3, "test-5", tuple(), INITIAL_VALUE,
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_A_SINGLE, "test-5").check();
 
     // whole list is updated after change of one element
     senderRoot.getMultipleA(0).setValue("test-6");
-    check(4, "test-5", tuple("test-6", "am2"), INITIAL_VALUE,
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_A_MANY, tuple("test-6", "am2")).check();
 
     senderRoot.addMultipleA(new A().setValue("test-7"));
-    check(5, "test-5", tuple("test-6", "am2", "test-7"), INITIAL_VALUE,
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_A_MANY, tuple("test-6", "am2", "test-7")).check();
 
     // --- B ---
     senderRoot.getB().setValue("test-8");
-    check(6, "test-5", tuple("test-6", "am2", "test-7"), "test-8",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_B_SINGLE, "test-8").check();
 
     senderRoot.getSingleB().setValue("test-9");
-    check(7, "test-5", tuple("test-6", "am2", "test-7"), "test-9",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_B_SINGLE, "test-9").check();
 
     senderRoot.getMaybeB().setValue("test-10");
-    check(8, "test-5", tuple("test-6", "am2", "test-7"), "test-10",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_B_SINGLE, "test-10").check();
 
     senderRoot.getMultipleB(0).setValue("test-11");
-    check(9, "test-5", tuple("test-6", "am2", "test-7"), "test-11-other",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_B_SINGLE, "test-11-other").check();
 
     // not connected, so no value is sent (manually wait)
     senderRoot.addMultipleB(new B().setValue("test-12-ignored"));
-    waitForMqtt();
-    check(9, "test-5", tuple("test-6", "am2", "test-7"), "test-11-other",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE, false);
+    checker.check();
 
     // connected, but current value is not sent (manually wait)
     assertTrue(senderRoot.getMultipleB(2).connect(mqttUri(TOPIC_B_SINGLE), false));
-    waitForMqtt();
-    check(9, "test-5", tuple("test-6", "am2", "test-7"), "test-11-other",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE, false);
+    checker.check();
 
     senderRoot.getMultipleB(2).setValue("test-12");
-    check(10, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            INITIAL_VALUE, tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_B_SINGLE, "test-12-other").check();
 
     // --- C ---
     senderRoot.getC().setValue("test-13");
-    check(11, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-13", tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_C_SINGLE, "pre-test-13").check();
 
     senderRoot.getSingleC().setValue("test-14");
-    check(12, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-14", tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_C_SINGLE, "pre-test-14").check();
 
     senderRoot.getMaybeC().setValue("test-15");
-    check(13, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple(), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_C_SINGLE, "pre-test-15").check();
 
     senderRoot.getMultipleC(1).setValue("test-16");
-    check(14, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16"), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_C_MANY, tuple("pre-cm1", "pre-test-16")).check();
 
     senderRoot.addMultipleC(new C().setValue("test-17"));
-    check(15, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), INITIAL_VALUE);
+    checker.incNumberOfValues().put(TOPIC_C_MANY, tuple("pre-cm1", "pre-test-16", "pre-test-17")).check();
 
     // --- D ---
     senderRoot.getD().setValue("test-18");
-    check(16, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-18-post");
+    checker.incNumberOfValues().put(TOPIC_D_SINGLE, "test-18-post").check();
 
     senderRoot.getSingleD().setValue("test-19");
-    check(17, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-19-post");
+    checker.incNumberOfValues().put(TOPIC_D_SINGLE, "test-19-post").check();
 
     senderRoot.getMaybeD().setValue("test-20");
-    check(18, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-20-post");
+    checker.incNumberOfValues().put(TOPIC_D_SINGLE, "test-20-post").check();
 
     senderRoot.getMultipleD(0).setValue("test-21");
-    check(19, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-21-other");
+    checker.incNumberOfValues().put(TOPIC_D_SINGLE, "test-21-other").check();
 
     // not connected, so no value is sent (manually wait)
     senderRoot.addMultipleD(new D().setValue("test-22-ignored"));
-    waitForMqtt();
-    check(19, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-21-other", false);
+    checker.check();
 
     // connected, but current value is not sent (manually wait)
     assertTrue(senderRoot.getMultipleD(2).connect(mqttUri(TOPIC_D_SINGLE), false));
-    waitForMqtt();
-    check(19, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-21-other", false);
+    checker.check();
 
     senderRoot.getMultipleD(2).setValue("test-22");
-    check(20, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-22-other");
+    checker.incNumberOfValues().put(TOPIC_D_SINGLE, "test-22-other").check();
 
 
     assertTrue(senderRoot.getMultipleB(1).disconnectSend(mqttUri(TOPIC_B_SINGLE)));
@@ -464,9 +293,7 @@ public class ForwardingTest extends AbstractMqttTest {
     assertTrue(senderRoot.getB().disconnectSend(mqttUri(TOPIC_B_SINGLE)));
     senderRoot.getB().setValue("test-27-ignored");
 
-    waitForMqtt();
-    check(20, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-22-other", false);
+    checker.check();
 
     // same for A
     assertTrue(senderRoot.disconnectMultipleAList(mqttUri(TOPIC_A_MANY)));
@@ -479,37 +306,7 @@ public class ForwardingTest extends AbstractMqttTest {
     assertTrue(senderRoot.disconnectA(mqttUri(TOPIC_A_SINGLE)));
     senderRoot.getA().setValue("test-31-ignored");
 
-    waitForMqtt();
-    check(20, "test-5", tuple("test-6", "am2", "test-7"), "test-12-other",
-            "pre-test-15", tuple("pre-cm1", "pre-test-16", "pre-test-17"), "test-22-other", false);
-  }
-
-  private void check(int valuesSent, String valueSingleA, Tuple valueManyA, String valueSingleB,
-                     String valueSingleC, Tuple valueManyC, String valueSingleD) {
-    check(valuesSent, valueSingleA, valueManyA, valueSingleB, valueSingleC, valueManyC, valueSingleD, true);
-  }
-
-  private void check(int valuesSent, String valueSingleA, Tuple valueManyA, String valueSingleB,
-                     String valueSingleC, Tuple valueManyC, String valueSingleD, boolean wait) {
-    if (wait) {
-      observer.awaitChange();
-    } else {
-      assertFalse(observer.hasChanged());
-    }
-
-    assertEquals(valuesSent, data.valuesSent);
-
-    assertThat(receiverRoot.getA().getValue()).as("A").isEqualTo(valueSingleA);
-    assertThat(receiverRoot.getManyAList()).extracting("Value").as("a-many")
-            .containsExactlyElementsOf(valueManyA.toList());
-
-    assertThat(receiverRoot.getB().getValue()).as("B").isEqualTo(valueSingleB);
-
-    assertThat(receiverRoot.getC().getValue()).as("C").isEqualTo(valueSingleC);
-    assertThat(receiverRoot.getManyCList()).extracting("Value").as("c-many")
-            .containsExactlyElementsOf(valueManyC.toList());
-
-    assertThat(receiverRoot.getD().getValue()).as("D").isEqualTo(valueSingleD);
+    checker.check();
   }
 
   @Override
@@ -520,15 +317,6 @@ public class ForwardingTest extends AbstractMqttTest {
     if (model != null) {
       model.ragconnectCloseConnections();
     }
-    observer.init();
-  }
-
-  static class Values<T> {
-    T unnamed;
-    T single;
-    T opt;
-    T list1;
-    T list2;
   }
 
   static class ReceiverData {
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java
index ce6bb40861239ce921f62714bba54937c9ad820e..46e944c560e072583982a2840bce57f9e66f6bab 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java
@@ -86,47 +86,7 @@ public class IncrementalDependencyTest extends AbstractMqttTest {
         "bStartPostfix",
         "bStartPostfix");
 
-    // send and check new value
-    sendData("101");
-    checkData(2, "a101",
-        "b101Postfix",
-        "b101Postfix");
-
-    // send and check same value
-    sendData("101");
-    checkData(2, "a101",
-        "b101Postfix",
-        "b101Postfix");
-
-    // send and check new value
-    sendData("201");
-    checkData(3, "a201",
-        "b201Postfix",
-        "b201Postfix");
-
-    // send and check new value (b1 should not change)
-    assertTrue(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1)));
-    sendData("301");
-    checkData(4, "a301",
-        3, "b201Postfix",
-        4, "b301Postfix");
-
-    // disconnecting again should yield false
-    assertFalse(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1)));
-
-    // send and check new value (b1 and b2 should not change)
-    assertTrue(b2.disconnectOutputOnB(mqttUri(TOPIC_OUT_B2)));
-    sendData("401");
-    checkData(5, "a401",
-        3, "b201Postfix",
-        4, "b301Postfix");
-
-    // send and check new value (nothing should not change)
-    assertTrue(model.disconnectOutputOnA(mqttUri(TOPIC_OUT_A)));
-    sendData("501");
-    checkData(5, "a401",
-        3, "b201Postfix",
-        4, "b301Postfix");
+    communicateBoth(1);
   }
 
   @Override
@@ -137,30 +97,34 @@ public class IncrementalDependencyTest extends AbstractMqttTest {
         null,
         null);
 
+    communicateBoth(0);
+  }
+
+  private void communicateBoth(int initialNumberOfValues) throws InterruptedException, IOException {
     // send and check new value
     sendData("102");
-    checkData(1, "a102",
+    checkData(initialNumberOfValues + 1, "a102",
         "b102Postfix",
         "b102Postfix");
 
     // send and check same value
     sendData("102");
-    checkData(1, "a102",
+    checkData(initialNumberOfValues + 1, "a102",
         "b102Postfix",
         "b102Postfix");
 
     // send and check new value
     sendData("202");
-    checkData(2, "a202",
+    checkData(initialNumberOfValues + 2, "a202",
         "b202Postfix",
         "b202Postfix");
 
     // send and check new value (b1 should not change)
     assertTrue(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1)));
     sendData("302");
-    checkData(3, "a302",
-        2, "b202Postfix",
-        3, "b302Postfix");
+    checkData(initialNumberOfValues + 3, "a302",
+            initialNumberOfValues + 2, "b202Postfix",
+            initialNumberOfValues + 3, "b302Postfix");
 
     // disconnecting again should yield false
     assertFalse(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1)));
@@ -168,16 +132,16 @@ public class IncrementalDependencyTest extends AbstractMqttTest {
     // send and check new value (b1 and b2 should not change)
     assertTrue(b2.disconnectOutputOnB(mqttUri(TOPIC_OUT_B2)));
     sendData("402");
-    checkData(4, "a402",
-        2, "b202Postfix",
-        3, "b302Postfix");
+    checkData(initialNumberOfValues + 4, "a402",
+            initialNumberOfValues + 2, "b202Postfix",
+            initialNumberOfValues + 3, "b302Postfix");
 
     // send and check new value (nothing should not change)
     assertTrue(model.disconnectOutputOnA(mqttUri(TOPIC_OUT_A)));
     sendData("502");
-    checkData(4, "a402",
-        2, "b202Postfix",
-        3, "b302Postfix");
+    checkData(initialNumberOfValues + 4, "a402",
+            initialNumberOfValues + 2, "b202Postfix",
+            initialNumberOfValues + 3, "b302Postfix");
   }
 
   @Override
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IndexedSendTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IndexedSendTest.java
index 75d7d16b18c64f7b5fd39c71acba81f92223a2af..a15d9990c44d0856c2f1c7af3f022e422d745c71 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IndexedSendTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IndexedSendTest.java
@@ -2,7 +2,6 @@ package org.jastadd.ragconnect.tests;
 
 import indexedSendInc.ast.*;
 import org.assertj.core.api.Assertions;
-import org.assertj.core.groups.Tuple;
 import org.junit.jupiter.api.Tag;
 
 import java.io.IOException;
@@ -31,8 +30,12 @@ public class IndexedSendTest extends AbstractMqttTest {
   private static final String TOPIC_A_MANY_SUFFIX_1 = "a-many-suffix/1";
   private static final String TOPIC_A_MANY_SUFFIX_2 = "a-many-suffix/2";
 
+  private static final String CHECK_MANY_A = "many-a";
+  private static final String CHECK_WITH_SUFFIX = "many-a-with-suffix";
+
   private MqttHandler handler;
   private ReceiverData data;
+  private TestUtils.TestChecker checker;
 
   private Root model;
   private SenderRoot senderRoot;
@@ -77,6 +80,17 @@ public class IndexedSendTest extends AbstractMqttTest {
     assertTrue(handler.newConnection(TOPIC_A_MANY_NORMAL_WILDCARD, bytes -> data.numberOfValues += 1));
     assertTrue(handler.newConnection(TOPIC_A_MANY_SUFFIX_WILDCARD, bytes -> data.numberOfValues += 1));
 
+    checker = new TestChecker();
+    checker.setActualNumberOfValues(() -> data.numberOfValues)
+            .setCheckForTuple(CHECK_MANY_A, (name, expected) ->
+                    Assertions.assertThat(receiverRoot.getManyAList()).extracting("Value")
+                            .as(name)
+                            .containsExactlyElementsOf(expected.toList()))
+            .setCheckForTuple(CHECK_WITH_SUFFIX, (name, expected) ->
+                    Assertions.assertThat(receiverRoot.getManyAWithSuffixList()).extracting("Value")
+                            .as(name)
+                            .containsExactlyElementsOf(expected.toList()));
+
     // connect receive
     assertTrue(receiverRoot.connectManyA(mqttUri(TOPIC_A_MANY_NORMAL_WILDCARD)));
     assertTrue(receiverRoot.connectManyAWithSuffix(mqttUri(TOPIC_A_MANY_SUFFIX_WILDCARD)));
@@ -103,90 +117,80 @@ public class IndexedSendTest extends AbstractMqttTest {
 
   @Override
   protected void communicateSendInitialValue() throws IOException, InterruptedException {
-    // Sink.ManyA           <-- Root.MultipleA
-    // Sink.ManyAWithSuffix <-- Root.MultipleAWithSuffix
-    check(4, tuple("am0", "am1"), tuple("am0post", "am1post"), false);
+    checker.addToNumberOfValues(4)
+            .put(CHECK_MANY_A, tuple("am0", "am1"))
+            .put(CHECK_WITH_SUFFIX, tuple("am0post", "am1post"));
 
     listA0.setValue("changedValue");
-    check(5, tuple("changedValue", "am1"), tuple("am0post", "am1post"));
+    checker.incNumberOfValues().put(CHECK_MANY_A, tuple("changedValue", "am1")).check();
 
     // setting same value must not change data, and must not trigger a new sent message
     listA0.setValue("changedValue");
-    check(5, tuple("changedValue", "am1"), tuple("am0post", "am1post"));
+    checker.check();
 
     listA1.setValue("");
-    check(6, tuple("changedValue", ""), tuple("am0post", "am1post"));
+    checker.incNumberOfValues().put(CHECK_MANY_A, tuple("changedValue", "")).check();
 
     listA1InSuffix.setValue("re");
-    check(7, tuple("changedValue", ""), tuple("am0post", "repost"));
+    checker.incNumberOfValues().put(CHECK_WITH_SUFFIX, tuple("am0post", "repost")).check();
 
     // adding a new element does not automatically send it
     A listA3InSuffix = createA("out");
     senderRoot.addMultipleAWithSuffix(listA3InSuffix);
-    check(7, tuple("changedValue", ""), tuple("am0post", "repost"));
+    checker.check();
 
     // only after connecting it, the element gets sent
     assertTrue(senderRoot.connectMultipleAWithSuffix(mqttUri(TOPIC_A_MANY_SUFFIX_2), 2, true));
-    check(8, tuple("changedValue", ""), tuple("am0post", "repost", "outpost"));
+    checker.incNumberOfValues().put(CHECK_WITH_SUFFIX, tuple("am0post", "repost", "outpost")).check();
 
     // after successful disconnect, no messages will be sent
     assertTrue(senderRoot.disconnectMultipleAWithSuffix(mqttUri(TOPIC_A_MANY_SUFFIX_0)));
     listA0InSuffix.setValue("willBeIgnored");
-    check(8, tuple("changedValue", ""), tuple("am0post", "repost", "outpost"));
+    checker.check();
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException {
-    check(0, tuple(), tuple(), false);
+    checker.put(CHECK_MANY_A, tuple())
+            .put(CHECK_WITH_SUFFIX, tuple());
+
+    communicateBoth();
+  }
+
+  private void communicateBoth() throws IOException {
+    // Sink.ManyA           <-- Root.MultipleA
+    // Sink.ManyAWithSuffix <-- Root.MultipleAWithSuffix
+    checker.check();
 
     assertEquals(listA0.getValue(), senderRoot._ragconnect_MultipleA(0).getValue());
     listA0.setValue("changedValue");
     assertEquals(listA0.getValue(), senderRoot._ragconnect_MultipleA(0).getValue());
-    check(1, tuple("changedValue"), tuple());
+    checker.incNumberOfValues().put(CHECK_MANY_A, tuple("changedValue")).check();
 
     // setting same value must not change data, and must not trigger a new sent message
     listA0.setValue("changedValue");
-    check(1, tuple("changedValue"), tuple());
+    checker.check();
 
     listA1.setValue("");
-    check(2, tuple("changedValue", ""), tuple());
+    checker.incNumberOfValues().put(CHECK_MANY_A, tuple("changedValue", "")).check();
 
     // first element in suffix-list
     listA1InSuffix.setValue("re");
-    check(3, tuple("changedValue", ""), tuple("repost"));
+    checker.incNumberOfValues().put(CHECK_WITH_SUFFIX, tuple("repost")).check();
 
     // adding a new element does not automatically send it
     A listA3InSuffix = createA("out");
     senderRoot.addMultipleAWithSuffix(listA3InSuffix);
-    check(3, tuple("changedValue", ""), tuple("repost"));
+    checker.check();
 
     // only after connecting it, the element gets sent
     assertTrue(senderRoot.connectMultipleAWithSuffix(mqttUri(TOPIC_A_MANY_SUFFIX_2), 2, true));
-    check(4, tuple("changedValue", ""), tuple("repost", "outpost"));
+    checker.incNumberOfValues().put(CHECK_WITH_SUFFIX, tuple("repost", "outpost")).check();
 
     // after successful disconnect, no messages will be sent
     assertTrue(senderRoot.disconnectMultipleAWithSuffix(mqttUri(TOPIC_A_MANY_SUFFIX_0)));
     listA0InSuffix.setValue("willBeIgnored");
-    check(4, tuple("changedValue", ""), tuple("repost", "outpost"));
-  }
-
-  private void check(int expectedNumberOfSentValues, Tuple valueManyA, Tuple valueManyAWithSuffix)
-          throws InterruptedException {
-    check(expectedNumberOfSentValues, valueManyA, valueManyAWithSuffix, true);
-  }
-
-  private void check(int expectedNumberOfSentValues, Tuple valueManyA, Tuple valueManyAWithSuffix, boolean wait)
-          throws InterruptedException {
-    if (wait) {
-      waitForMqtt();
-    }
-    assertEquals(expectedNumberOfSentValues, data.numberOfValues, "expectedNumberOfSentValues");
-    Assertions.assertThat(receiverRoot.getManyAList()).extracting("Value")
-            .as("many-a")
-            .containsExactlyElementsOf(valueManyA.toList());
-    Assertions.assertThat(receiverRoot.getManyAWithSuffixList()).extracting("Value")
-            .as("many-a-with-suffix")
-            .containsExactlyElementsOf(valueManyAWithSuffix.toList());
+    checker.check();
   }
 
   @Override
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MappingTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MappingTest.java
index c8ac3b889d41dafbbae1717a78f7066f70ad21b7..f1cafb03ff6900b9859600da79b4d6103bc140f8 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MappingTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MappingTest.java
@@ -119,20 +119,7 @@ public class MappingTest extends AbstractMqttTest {
     checkSendData(1, 1, (short) 1, 1, 1.01f, 1.01d, (char) 1, 1, false);
     // no check for initial received data (no input set yet)
 
-    // send first value
-    sendAndSetData("21", "31");
-    checkSendData(2, 21, (short) 21, 21, 21.01f, 21.01d, (char) 21, 1, false);
-    checkReceiveData(31, (short) 31, 31, 31.01f, 31.01d, (char) 31, true);
-
-    // send same value
-    sendAndSetData("21", "31");
-    checkSendData(2, 21, (short) 21, 21, 21.01f, 21.01d, (char) 21, 1, false);
-    checkReceiveData(31, (short) 31, 31, 31.01f, 31.01d, (char) 31, true);
-
-    // send new value
-    sendAndSetData("22", "32");
-    checkSendData(3, 22, (short) 22, 22, 22.01f, 22.01d, (char) 22, 2, true);
-    checkReceiveData(32, (short) 32, 32, 32.01f, 32.01d, (char) 32, true);
+    communicateBoth(1);
   }
 
   @Override
@@ -140,20 +127,24 @@ public class MappingTest extends AbstractMqttTest {
     checkSendData(0, 0, (short) 0, 0, 0f, 0d, (char) 0, 0, false);
     // no check for initial received data (no input set yet)
 
+    communicateBoth(0);
+  }
+
+  private void communicateBoth(int initialNumberOfValues) throws InterruptedException {
     // send first value
     sendAndSetData("41", "51");
-    checkSendData(1, 41, (short) 41, 41, 41.01f, 41.01d, (char) 41, 1, true);
-    checkReceiveData(51, (short) 51, 51, 51.01f, 51.01d, (char) 51, true);
+    checkSendData(initialNumberOfValues + 1, 41, (short) 41, 41, 41.01f, 41.01d, (char) 41, initialNumberOfValues + 1, true);
+    checkReceiveData(51, (short) 51, 51, 51.01f, 51.01d, (char) 51);
 
     // send same value
     sendAndSetData("41", "51");
-    checkSendData(1, 41, (short) 41, 41, 41.01f, 41.01d, (char) 41, 1, true);
-    checkReceiveData(51, (short) 51, 51, 51.01f, 51.01d, (char) 51, true);
+    checkSendData(initialNumberOfValues + 1, 41, (short) 41, 41, 41.01f, 41.01d, (char) 41, initialNumberOfValues + 1, true);
+    checkReceiveData(51, (short) 51, 51, 51.01f, 51.01d, (char) 51);
 
     // send new value
     sendAndSetData("42", "52");
-    checkSendData(2, 42, (short) 42, 42, 42.01f, 42.01d, (char) 42, 1, true);
-    checkReceiveData(52, (short) 52, 52, 52.01f, 52.01d, (char) 52, true);
+    checkSendData(initialNumberOfValues + 2, 42, (short) 42, 42, 42.01f, 42.01d, (char) 42, initialNumberOfValues + 1, true);
+    checkReceiveData(52, (short) 52, 52, 52.01f, 52.01d, (char) 52);
   }
 
   @Override
@@ -193,14 +184,14 @@ public class MappingTest extends AbstractMqttTest {
     assertEquals(expectedBoolean, data.lastNativeBooleanValue);
   }
 
-  private void checkReceiveData(int expectedInt, short expectedShort, long expectedLong, float expectedFloat, double expectedDouble, char expectedChar, boolean expectedBoolean) {
+  private void checkReceiveData(int expectedInt, short expectedShort, long expectedLong, float expectedFloat, double expectedDouble, char expectedChar) {
     assertEquals(expectedInt, natives.getIntValue());
     assertEquals(expectedShort, natives.getShortValue());
     assertEquals(expectedLong, natives.getLongValue());
     assertEquals(expectedFloat, natives.getFloatValue(), TestUtils.DELTA);
     assertEquals(expectedDouble, natives.getDoubleValue(), TestUtils.DELTA);
     assertEquals(expectedChar, natives.getCharValue());
-    assertEquals(expectedBoolean, natives.getBooleanValue());
+    assertTrue(natives.getBooleanValue());
 
     assertEquals(expectedInt, boxes.getIntValue());
     assertEquals(expectedShort, boxes.getShortValue());
@@ -208,7 +199,7 @@ public class MappingTest extends AbstractMqttTest {
     assertEquals(expectedFloat, boxes.getFloatValue(), TestUtils.DELTA);
     assertEquals(expectedDouble, boxes.getDoubleValue(), TestUtils.DELTA);
     assertEquals(expectedChar, boxes.getCharValue());
-    assertEquals(expectedBoolean, boxes.getBooleanValue());
+    assertEquals(true, boxes.getBooleanValue());
   }
 
   private static class ReceiverData {
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read1Write2Test.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read1Write2Test.java
index 11bbd8f632870ba1d41394e9c5775f39995fb62c..4deccefe8865be8a3bab05ba7ffad560ab83c09f 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read1Write2Test.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read1Write2Test.java
@@ -116,23 +116,7 @@ public class Read1Write2Test extends AbstractMqttTest {
     // check initial value
     checkData(1, Integer.parseInt(INITIAL_VALUE), prefixed(INITIAL_VALUE), 1, Integer.parseInt(INITIAL_VALUE), prefixed(INITIAL_VALUE));
 
-    // set new value
-    sendData("2", "3");
-
-    // check new value
-    checkData(2, 2, prefixed("2"), 2, 3, prefixed("3"));
-
-    // set new value
-    sendData("4", "4");
-
-    // check new value
-    checkData(3, 4, prefixed("4"), 3, 4, prefixed("4"));
-
-    // set new value only for same
-    setDataOnlySame("77");
-
-    // check new value
-    checkData(4, 77, prefixed("77"), 3, 4, prefixed("4"));
+    communicateBoth(1);
   }
 
   @Override
@@ -140,23 +124,27 @@ public class Read1Write2Test extends AbstractMqttTest {
 // check initial value
     checkData(0, null, null, 0, null, null);
 
+    communicateBoth(0);
+  }
+
+  private void communicateBoth(int initialNumberOfValues) throws InterruptedException {
     // set new value
     sendData("2", "3");
 
     // check new value
-    checkData(1, 2, prefixed("2"), 1, 3, prefixed("3"));
+    checkData(initialNumberOfValues + 1, 2, prefixed("2"), initialNumberOfValues + 1, 3, prefixed("3"));
 
     // set new value
     sendData("4", "4");
 
     // check new value
-    checkData(2, 4, prefixed("4"), 2, 4, prefixed("4"));
+    checkData(initialNumberOfValues + 2, 4, prefixed("4"), initialNumberOfValues + 2, 4, prefixed("4"));
 
     // set new value only for same
-    setDataOnlySame("78");
+    handler.publish(TOPIC_SAME_READ, "78".getBytes());
 
     // check new value
-    checkData(3, 78, prefixed("78"), 2, 4, prefixed("4"));
+    checkData(initialNumberOfValues + 3, 78, prefixed("78"), initialNumberOfValues + 2, 4, prefixed("4"));
   }
 
   @Override
@@ -178,10 +166,6 @@ public class Read1Write2Test extends AbstractMqttTest {
     publisher.publish(TOPIC_DIFFERENT_READ, inputDifferent.getBytes());
   }
 
-  private void setDataOnlySame(String inputSame) {
-    handler.publish(TOPIC_SAME_READ, inputSame.getBytes());
-  }
-
   private void checkData(int numberOfSameValues, Integer lastSameIntValue, String lastSameStringValue,
                          int numberOfDifferentValues, Integer lastDifferentIntValue,
                          String lastDifferentStringValue) throws InterruptedException {
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read2Write1Test.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read2Write1Test.java
index 7d9742b864daf44eb95fa934b81dc0963c2450e5..f931c13c92616e52716fd1b4f5aa26e3f838dac9 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read2Write1Test.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Read2Write1Test.java
@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * Test case "read-1-write-2".
+ * Test case "read-2-write-1".
  *
  * @author rschoene - Initial contribution
  */
@@ -105,54 +105,39 @@ public class Read2Write1Test extends AbstractMqttTest {
     checkData(1, Integer.parseInt(INITIAL_VALUE + INITIAL_VALUE),
         1, Integer.parseInt(INITIAL_VALUE + INITIAL_VALUE));
 
-    // set new value
-    sendData(true, "2", true, "3");
-
-    // check new value. same: 2, 0. different: 3, 0.
-    checkData(2, 20,
-        2, 30);
-
-    // set new value
-    sendData(false, "4", false, "4");
-
-    // check new value. same: 2, 4. different: 3, 4.
-    checkData(3, 24,
-        3, 34);
-
-    // set new value only for same
-    setDataOnlySame("77");
-
-    // check new value. same: 77, 4. different: 3, 4.
-    checkData(4, 774,
-        3, 34);
+    communicateBoth(1);
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws InterruptedException {
     // check initial value
     checkData(0, null,
-        0, null);
+            0, null);
 
+    communicateBoth(0);
+  }
+
+  private void communicateBoth(int initialNumberOfValues) throws InterruptedException {
     // set new value
     sendData(true, "2", true, "3");
 
     // check new value. same: 2, 0. different: 3, 0.
-    checkData(1, 20,
-        1, 30);
+    checkData(initialNumberOfValues + 1, 20,
+            initialNumberOfValues + 1, 30);
 
     // set new value
     sendData(false, "4", false, "4");
 
     // check new value. same: 2, 4. different: 3, 4.
-    checkData(2, 24,
-        2, 34);
+    checkData(initialNumberOfValues + 2, 24,
+            initialNumberOfValues + 2, 34);
 
     // set new value only for same
-    setDataOnlySame("78");
+    publisher.publish(TOPIC_SAME_READ1, "78".getBytes());
 
     // check new value. same: 78, 4. different: 3, 4.
-    checkData(3, 784,
-        2, 34);
+    checkData(initialNumberOfValues + 3, 784,
+            initialNumberOfValues + 2, 34);
   }
 
   @Override
@@ -173,10 +158,6 @@ public class Read2Write1Test extends AbstractMqttTest {
         inputDifferent.getBytes());
   }
 
-  private void setDataOnlySame(String inputSame) {
-    publisher.publish(TOPIC_SAME_READ1, inputSame.getBytes());
-  }
-
   private void checkData(int numberOfSameValues, Integer lastSameIntValue,
                          int numberOfDifferentValues, Integer lastDifferentIntValue)
       throws InterruptedException {
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java
index 3fb3e225d1003fb92b576a3fa1bb345a6b0302d9..5e6c94ff596909e6f70a0b84e6562ab4ec171d7d 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java
@@ -214,7 +214,7 @@ public class TestUtils {
         if (actual == null) {
           fail("No actual getter defined for " + name);
         }
-        awaitMqtt().alias(name).until(actual, Predicate.isEqual(expected));
+        awaitMqtt().alias(name + " == " + expected).until(actual, Predicate.isEqual(expected));
       }
     }
     static class ValuesToCompare<T> {
@@ -271,6 +271,7 @@ public class TestUtils {
       }
     }
     private final static String NUMBER_OF_VALUES = "numberOfValues";
+    public final ValuesToCompare<Object> objectValues = new ValuesToCompare<>(this);
     public final ValuesToCompare<String> stringValues = new ValuesToCompare<>(this);
     public final ValuesToCompare<Tuple> tupleValues = new ValuesToCompare<>(this);
     public final IntegerValuesToCompare intValues = new IntegerValuesToCompare(this);
@@ -289,6 +290,18 @@ public class TestUtils {
       return intValues.setActualNumberOfValues(actual);
     }
 
+    public TestChecker alwaysWait() {
+      return setActualNumberOfValues(() -> 0);
+    }
+
+    public TestChecker put(String name, Object expected) {
+      return objectValues.put(name, expected);
+    }
+
+    public TestChecker setCheckForObject(String name, BiConsumer<String, Object> check) {
+      return objectValues.setCheck(name, check);
+    }
+
     public TestChecker setActualString(String name, Callable<String> actual) {
       return stringValues.setActual(name, actual);
     }
@@ -341,6 +354,7 @@ public class TestUtils {
       }
       intValues.get(NUMBER_OF_VALUES).checkAwait(NUMBER_OF_VALUES);
 
+      objectValues.forEach((name, aae) -> aae.check(name));
       stringValues.forEach((name, aae) -> aae.check(name));
       tupleValues.forEach((name, aae) -> aae.check(name));
       intValues.forEach((name, aae) -> {
@@ -353,9 +367,9 @@ public class TestUtils {
   }
 
   public static class IntList {
-    private final List<Integer> integers = newArrayList();
+    private final List<Integer> integers;
     public IntList(Integer... values) {
-      addAll(integers, values);
+      integers = Arrays.stream(values).filter(Objects::nonNull).collect(Collectors.toList());
     }
 
     public List<Integer> toList() {
@@ -572,19 +586,19 @@ public class TestUtils {
     }
   }
 
-  static class ChangeObserver {
+  public static class ChangeObserver {
     Map<Supplier<String>, String> callableToPrevious = new HashMap<>();
     private Callable<Boolean> hasChanged;
 
     @SafeVarargs
-    final void init(Supplier<String>... suppliers) {
+    public final void init(Supplier<String>... suppliers) {
       callableToPrevious.clear();
       Arrays.stream(suppliers).forEach(callable -> callableToPrevious.put(callable, callable.get()));
       hasChanged = () -> callableToPrevious.entrySet().stream()
               .anyMatch(entry -> !entry.getKey().get().equals(entry.getValue()));
     }
 
-    void start() {
+    public void start() {
       updatePrevious();
     }
 
@@ -592,12 +606,12 @@ public class TestUtils {
       callableToPrevious.keySet().forEach(callable -> callableToPrevious.put(callable, callable.get()));
     }
 
-    void awaitChange() {
+    public void awaitChange() {
       awaitMqtt().until(hasChanged);
       updatePrevious();
     }
 
-    boolean hasChanged() {
+    public boolean hasChanged() {
       try {
         return hasChanged.call();
       } catch (Exception e) {
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java
deleted file mode 100644
index 1a29e11885757db528f2d6da2b37297119b751a1..0000000000000000000000000000000000000000
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java
+++ /dev/null
@@ -1,298 +0,0 @@
-package org.jastadd.ragconnect.tests;
-
-import tokenValueSend.ast.*;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-import static org.jastadd.ragconnect.tests.TestUtils.mqttUri;
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * Test case "tokenValueSend".
- *
- * @author rschoene - Initial contribution
- */
-public class TokenValueSendTest extends AbstractMqttTest {
-  // TODO split into incremental and manual test
-
-  private static final String TOPIC_SEND_ONE = "one/value/out";
-
-  private static final String TOPIC_RECEIVE_TWO = "two/value/in";
-  private static final String TOPIC_SEND_TWO = "two/value/out";
-
-  private static final String TOPIC_RECEIVE_THREE_VALUE = "three/value/in";
-  private static final String TOPIC_SEND_THREE_VALUE = "three/value/out";
-  private static final String TOPIC_SEND_THREE_OTHER = "three/other/out";
-
-  private static final String INITIAL_VALUE = "Start";
-
-  private MqttHandler handler;
-  private A model;
-  private OnlySend one;
-  private ReceiveAndSend two;
-  private ReceiveSendAndDepend three;
-
-  private ReceiverData dataOne;
-  private ReceiverData dataTwo;
-  private ReceiverData dataThree;
-  private ReceiverData dataThreeOther;
-
-  @Override
-  protected void createModel() {
-    // Setting value for Input without dependencies does not trigger any updates
-    model = new A();
-
-    one = new OnlySend();
-    one.setValue(INITIAL_VALUE);
-    model.setOnlySend(one);
-
-    two = new ReceiveAndSend();
-    two.setValue(INITIAL_VALUE);
-    model.setReceiveAndSend(two);
-
-    three = new ReceiveSendAndDepend();
-    three.setValue(INITIAL_VALUE);
-    model.setReceiveSendAndDepend(three);
-  }
-
-  @Override
-  protected void setupReceiverAndConnect() throws IOException {
-    model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
-
-    handler = new MqttHandler().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost());
-    assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS));
-
-    three.addDependency1(three);
-
-    dataOne = new ReceiverData();
-    dataTwo = new ReceiverData();
-    dataThree = new ReceiverData();
-    dataThreeOther = new ReceiverData();
-
-    handler.newConnection(TOPIC_SEND_ONE, bytes -> {
-      dataOne.numberOfStringValues += 1;
-      dataOne.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
-    });
-    handler.newConnection(TOPIC_SEND_TWO, bytes -> {
-      dataTwo.numberOfStringValues += 1;
-      dataTwo.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
-    });
-
-    handler.newConnection(TOPIC_SEND_THREE_VALUE, bytes -> {
-      dataThree.numberOfStringValues += 1;
-      dataThree.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
-    });
-    handler.newConnection(TOPIC_SEND_THREE_OTHER, bytes -> {
-      dataThreeOther.numberOfStringValues += 1;
-      dataThreeOther.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
-    });
-
-    assertTrue(one.connectValue(mqttUri(TOPIC_SEND_ONE), isWriteCurrentValue()));
-    assertTrue(two.connectValue(mqttUri(TOPIC_RECEIVE_TWO)));
-    assertTrue(two.connectValue(mqttUri(TOPIC_SEND_TWO), isWriteCurrentValue()));
-    assertTrue(three.connectValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE)));
-    assertTrue(three.connectValue(mqttUri(TOPIC_SEND_THREE_VALUE), isWriteCurrentValue()));
-    assertTrue(three.connectOtherOutput(mqttUri(TOPIC_SEND_THREE_OTHER), isWriteCurrentValue()));
-  }
-
-  @Override
-  protected void communicateSendInitialValue() throws InterruptedException, IOException {
-    // check initial value
-    checkData(1, "Start-Post",
-        1, "Start-Post",
-        1, "Start-Post",
-        1, "Start-T-Post");
-
-    // send new value
-    sendData("200", "300");
-    checkData(1, "Start-Post",
-        2, "Pre-200-Post",
-        2, "Pre-300-Post",
-        2, "Pre-300-T-Post");
-
-    // set new value
-    setData("101", "201", "301");
-    checkData(2, "101-Post",
-        3, "201-Post",
-        3, "301-Post",
-        3, "301-T-Post");
-
-    // send the same values (will not be sent again)
-    setData("101", "201", "301");
-    checkData(2, "101-Post",
-        3, "201-Post",
-        3, "301-Post",
-        3, "301-T-Post");
-
-    // send values with prefixes imitating receiving
-    setData("102", "Pre-202", "Pre-302");
-    checkData(3, "102-Post",
-        4, "Pre-202-Post",
-        4, "Pre-302-Post",
-        4, "Pre-302-T-Post");
-
-    // send the same values (will not be sent again, because previously prefixed)
-    sendData("202", "302");
-    checkData(3, "102-Post",
-        4, "Pre-202-Post",
-        4, "Pre-302-Post",
-        4, "Pre-302-T-Post");
-
-    // new values for two and three, but two will not send updated value
-    assertTrue(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO)));
-    sendData("203", "303");
-    checkData(3, "102-Post",
-        4, "Pre-202-Post",
-        5, "Pre-303-Post",
-        5, "Pre-303-T-Post");
-    assertEquals("Pre-203", two.getValue());
-
-    // can not disconnect again, and also not for different topic
-    assertFalse(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO)));
-    assertFalse(two.disconnectSendValue(mqttUri(TOPIC_RECEIVE_TWO)));
-
-    // new values for two and three, but two will neither receive nor send updated value
-    assertTrue(two.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_TWO)));
-    sendData("204", "304");
-    checkData(3, "102-Post",
-        4, "Pre-202-Post",
-        6, "Pre-304-Post",
-        6, "Pre-304-T-Post");
-    assertEquals("Pre-203", two.getValue());
-
-    // new values for three, but it will not receive updated value, and, thus, not send it either
-    assertTrue(three.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE)));
-    sendData("204", "305");
-    checkData(3, "102-Post",
-        4, "Pre-202-Post",
-        6, "Pre-304-Post",
-        6, "Pre-304-T-Post");
-    assertEquals("Pre-203", two.getValue());
-
-    // disconnect send is possible
-    assertTrue(three.disconnectSendValue(mqttUri(TOPIC_SEND_THREE_VALUE)));
-  }
-
-  @Override
-  protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException {
-    // check initial value
-    checkData(0, null,
-        0, null,
-        0, null,
-        0, null);
-
-    // send new value
-    sendData("210", "310");
-    checkData(0, null,
-        1, "Pre-210-Post",
-        1, "Pre-310-Post",
-        1, "Pre-310-T-Post");
-
-    // set new value
-    setData("111", "211", "311");
-    checkData(1, "111-Post",
-        2, "211-Post",
-        2, "311-Post",
-        2, "311-T-Post");
-
-    // send the same values (will not be sent again)
-    setData("111", "211", "311");
-    checkData(1, "111-Post",
-        2, "211-Post",
-        2, "311-Post",
-        2, "311-T-Post");
-
-    // send values with prefixes imitating receiving
-    setData("112", "Pre-212", "Pre-312");
-    checkData(2, "112-Post",
-        3, "Pre-212-Post",
-        3, "Pre-312-Post",
-        3, "Pre-312-T-Post");
-
-    // send the same values (will not be sent again, because previously prefixed)
-    sendData("212", "312");
-    checkData(2, "112-Post",
-        3, "Pre-212-Post",
-        3, "Pre-312-Post",
-        3, "Pre-312-T-Post");
-
-    // new values for two and three, but two will not send updated value
-    assertTrue(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO)));
-    sendData("213", "313");
-    checkData(2, "112-Post",
-        3, "Pre-212-Post",
-        4, "Pre-313-Post",
-        4, "Pre-313-T-Post");
-    assertEquals("Pre-213", two.getValue());
-
-    // can not disconnect again, and also not for different topic
-    assertFalse(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO)));
-    assertFalse(two.disconnectSendValue(mqttUri(TOPIC_RECEIVE_TWO)));
-
-    // new values for two and three, but two will neither receive nor send updated value
-    assertTrue(two.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_TWO)));
-    sendData("214", "314");
-    checkData(2, "112-Post",
-        3, "Pre-212-Post",
-        5, "Pre-314-Post",
-        5, "Pre-314-T-Post");
-    assertEquals("Pre-213", two.getValue());
-
-    // new values for three, but it will not receive updated value, and, thus, not send it either
-    assertTrue(three.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE)));
-    sendData("214", "315");
-    checkData(2, "112-Post",
-        3, "Pre-212-Post",
-        5, "Pre-314-Post",
-        5, "Pre-314-T-Post");
-    assertEquals("Pre-213", two.getValue());
-
-    // disconnect send is possible
-    assertTrue(three.disconnectSendValue(mqttUri(TOPIC_SEND_THREE_VALUE)));
-  }
-
-  @Override
-  public void closeConnections() {
-    if (handler != null) {
-      handler.close();
-    }
-    if (model != null) {
-      model.ragconnectCloseConnections();
-    }
-  }
-
-  private void sendData(String inputTwo, String inputThree) {
-    publisher.publish(TOPIC_RECEIVE_TWO, inputTwo.getBytes());
-    publisher.publish(TOPIC_RECEIVE_THREE_VALUE, inputThree.getBytes());
-  }
-
-  private void setData(String inputOne, String inputTwo, String inputThree) {
-    one.setValue(inputOne);
-    two.setValue(inputTwo);
-    three.setValue(inputThree);
-  }
-
-  private void checkData(int numberOfOneValues, String lastOneStringValue,
-                         int numberOfTwoValues, String lastTwoStringValue,
-                         int numberOfThreeValues, String lastThreeStringValue,
-                         int numberOfOtherValues, String lastOtherStringValue
-  ) throws InterruptedException {
-    TestUtils.waitForMqtt();
-    dataOne.assertEqualData(numberOfOneValues, lastOneStringValue);
-    dataTwo.assertEqualData(numberOfTwoValues, lastTwoStringValue);
-    dataThree.assertEqualData(numberOfThreeValues, lastThreeStringValue);
-    dataThreeOther.assertEqualData(numberOfOtherValues, lastOtherStringValue);
-  }
-
-  private static class ReceiverData {
-    String lastStringValue;
-    int numberOfStringValues = 0;
-
-    public void assertEqualData(int expectedNumberOfValues, String expectedLastValue) {
-      assertEquals(expectedNumberOfValues, this.numberOfStringValues);
-      assertEquals(expectedLastValue, this.lastStringValue);
-    }
-  }
-
-}
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java
index d630f5eb46b0d2cfe525647a9061725b7297ff49..4c1be6b4c25ef67360f7fc7dd898afc3ad1d8168 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java
@@ -1,5 +1,6 @@
 package org.jastadd.ragconnect.tests;
 
+import org.jastadd.ragconnect.tests.TestUtils.TestChecker;
 import org.junit.jupiter.api.Tag;
 import via.ast.A;
 import via.ast.MqttHandler;
@@ -46,6 +47,7 @@ public class ViaTest extends AbstractMqttTest {
   private static final String NOT_MAPPED = "<html><body><h2>404 Not found</h2></body></html>";
 
   private MqttHandler handler;
+  private TestChecker checker;
   private A model;
   private ReceiverData dataMqtt2Mqtt;
   private ReceiverData dataRest2Mqtt;
@@ -100,6 +102,9 @@ public class ViaTest extends AbstractMqttTest {
       dataBoth2Mqtt.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
     });
 
+    checker = new TestChecker();
+    checker.setActualNumberOfValues(() -> dataMqtt2Mqtt.numberOfStringValues);
+
     Client client = ClientBuilder.newClient();
     dataRest2Rest = client.target(REST_SERVER_BASE_URL + PATH_REST_2_REST_SEND);
     dataMqtt2Rest = client.target(REST_SERVER_BASE_URL + PATH_MQTT_2_REST_SEND);
@@ -125,6 +130,7 @@ public class ViaTest extends AbstractMqttTest {
   @Override
   protected void communicateSendInitialValue() throws InterruptedException, IOException {
     // check initial value
+    checker.addToNumberOfValues(1);
     checkData(1, "100-M2M-ToMqtt",
         "200-R2R-ToRest",
         "300-M2R-ToRest",
@@ -132,195 +138,109 @@ public class ViaTest extends AbstractMqttTest {
         1, "500-B2M-ToMqtt",
         "500-B2R-ToRest");
 
-    sendData("101", "201", "301", "401");
-    sendDataForBoth("501", true);
-
-    // check new value
-    checkData(2, "FromMqtt-101-M2M-ToMqtt",
-        "FromRest-201-R2R-ToRest",
-        "FromMqtt-301-M2R-ToRest",
-        2, "FromRest-401-R2M-ToMqtt",
-        2, "501-B2M-ToMqtt",
-        "501-B2R-ToRest");
-
-    // send value only for bothInput via REST
-    sendDataForBoth("502", false);
-
-    // check this value
-    checkData(2, "FromMqtt-101-M2M-ToMqtt",
-        "FromRest-201-R2R-ToRest",
-        "FromMqtt-301-M2R-ToRest",
-        2, "FromRest-401-R2M-ToMqtt",
-        3, "502-B2M-ToMqtt",
-        "502-B2R-ToRest");
-
-    // send same value only for bothInput via MQTT
-    sendDataForBoth("502", true);
-
-    // check this value
-    checkData(2, "FromMqtt-101-M2M-ToMqtt",
-        "FromRest-201-R2R-ToRest",
-        "FromMqtt-301-M2R-ToRest",
-        2, "FromRest-401-R2M-ToMqtt",
-        3, "502-B2M-ToMqtt",
-        "502-B2R-ToRest");
-
-    // send values for other things
-    sendData("102", "202", "302", "402");
-
-    // check this value
-    checkData(3, "FromMqtt-102-M2M-ToMqtt",
-        "FromRest-202-R2R-ToRest",
-        "FromMqtt-302-M2R-ToRest",
-        3, "FromRest-402-R2M-ToMqtt",
-        3, "502-B2M-ToMqtt",
-        "502-B2R-ToRest");
-
-    // send same values again for other things
-    sendData("102", "202", "302", "402");
-
-    // check this value
-    checkData(3, "FromMqtt-102-M2M-ToMqtt",
-        "FromRest-202-R2R-ToRest",
-        "FromMqtt-302-M2R-ToRest",
-        3, "FromRest-402-R2M-ToMqtt",
-        3, "502-B2M-ToMqtt",
-        "502-B2R-ToRest");
-
-    // send 503 over mqtt while disconnected should not change anything
-    assertTrue(model.disconnectBoth2BothInput(mqttUri(TOPIC_BOTH_MQTT_RECEIVE)));
-    sendDataForBoth("503", true);
-    checkData(3, "FromMqtt-102-M2M-ToMqtt",
-        "FromRest-202-R2R-ToRest",
-        "FromMqtt-302-M2R-ToRest",
-        3, "FromRest-402-R2M-ToMqtt",
-        3, "502-B2M-ToMqtt",
-        "502-B2R-ToRest");
-
-    // send 504 over rest while still connected should update
-    sendDataForBoth("504", false);
-    checkData(3, "FromMqtt-102-M2M-ToMqtt",
-        "FromRest-202-R2R-ToRest",
-        "FromMqtt-302-M2R-ToRest",
-        3, "FromRest-402-R2M-ToMqtt",
-        4, "504-B2M-ToMqtt",
-        "504-B2R-ToRest");
-
-    // send 505 over rest while also disconnected should not change anything
-    assertTrue(model.disconnectBoth2BothInput(restUri(PATH_BOTH_REST_RECEIVE, REST_PORT)));
-    sendDataForBoth("505", false);
-    checkData(3, "FromMqtt-102-M2M-ToMqtt",
-        "FromRest-202-R2R-ToRest",
-        "FromMqtt-302-M2R-ToRest",
-        3, "FromRest-402-R2M-ToMqtt",
-        4, "504-B2M-ToMqtt",
-        "504-B2R-ToRest");
-
-    // send new values. value over rest while sender disconnected does not provide a value anymore
-    assertTrue(model.disconnectRest2RestOutput(restUri(PATH_REST_2_REST_SEND, REST_PORT)));
-    assertTrue(model.disconnectMqtt2RestOutput(restUri(PATH_MQTT_2_REST_SEND, REST_PORT)));
-    sendData("103", "203", "303", "403");
-    checkData(4, "FromMqtt-103-M2M-ToMqtt",
-        NOT_MAPPED,
-        NOT_MAPPED,
-        4, "FromRest-403-R2M-ToMqtt",
-        4, "504-B2M-ToMqtt",
-        "504-B2R-ToRest");
+    communicateBoth(1);
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException {
     // check initial value
     checkData(0, null,
-        "200-R2R-ToRest",
-        "300-M2R-ToRest",
-        0, null,
-        0, null,
-        "500-B2R-ToRest");
+            "200-R2R-ToRest",
+            "300-M2R-ToRest",
+            0, null,
+            0, null,
+            "500-B2R-ToRest");
+
+    communicateBoth(0);
+  }
 
+  private void communicateBoth(int initialNumberOfValues) throws IOException {
     sendData("111", "211", "311", "411");
     sendDataForBoth("511", true);
-    checkData(1, "FromMqtt-111-M2M-ToMqtt",
+    checker.incNumberOfValues();
+    checkData(initialNumberOfValues + 1, "FromMqtt-111-M2M-ToMqtt",
         "FromRest-211-R2R-ToRest",
         "FromMqtt-311-M2R-ToRest",
-        1, "FromRest-411-R2M-ToMqtt",
-        1, "511-B2M-ToMqtt",
+        initialNumberOfValues + 1, "FromRest-411-R2M-ToMqtt",
+        initialNumberOfValues + 1, "511-B2M-ToMqtt",
         "511-B2R-ToRest");
 
     // send value only for bothInput via REST
     sendDataForBoth("512", false);
-    checkData(1, "FromMqtt-111-M2M-ToMqtt",
+    checkData(initialNumberOfValues + 1, "FromMqtt-111-M2M-ToMqtt",
         "FromRest-211-R2R-ToRest",
         "FromMqtt-311-M2R-ToRest",
-        1, "FromRest-411-R2M-ToMqtt",
-        2, "512-B2M-ToMqtt",
+        initialNumberOfValues + 1, "FromRest-411-R2M-ToMqtt",
+        initialNumberOfValues + 2, "512-B2M-ToMqtt",
         "512-B2R-ToRest");
 
     // send same value only for bothInput via MQTT
     sendDataForBoth("512", true);
-    checkData(1, "FromMqtt-111-M2M-ToMqtt",
+    checkData(initialNumberOfValues + 1, "FromMqtt-111-M2M-ToMqtt",
         "FromRest-211-R2R-ToRest",
         "FromMqtt-311-M2R-ToRest",
-        1, "FromRest-411-R2M-ToMqtt",
-        2, "512-B2M-ToMqtt",
+        initialNumberOfValues + 1, "FromRest-411-R2M-ToMqtt",
+        initialNumberOfValues + 2, "512-B2M-ToMqtt",
         "512-B2R-ToRest");
 
     // send values for other things
     sendData("112", "212", "312", "412");
-    checkData(2, "FromMqtt-112-M2M-ToMqtt",
+    checker.incNumberOfValues();
+    checkData(initialNumberOfValues + 2, "FromMqtt-112-M2M-ToMqtt",
         "FromRest-212-R2R-ToRest",
         "FromMqtt-312-M2R-ToRest",
-        2, "FromRest-412-R2M-ToMqtt",
-        2, "512-B2M-ToMqtt",
+        initialNumberOfValues + 2, "FromRest-412-R2M-ToMqtt",
+        initialNumberOfValues + 2, "512-B2M-ToMqtt",
         "512-B2R-ToRest");
 
     // send same values again for other things
     sendData("112", "212", "312", "412");
-    checkData(2, "FromMqtt-112-M2M-ToMqtt",
+    checkData(initialNumberOfValues + 2, "FromMqtt-112-M2M-ToMqtt",
         "FromRest-212-R2R-ToRest",
         "FromMqtt-312-M2R-ToRest",
-        2, "FromRest-412-R2M-ToMqtt",
-        2, "512-B2M-ToMqtt",
+        initialNumberOfValues + 2, "FromRest-412-R2M-ToMqtt",
+        initialNumberOfValues + 2, "512-B2M-ToMqtt",
         "512-B2R-ToRest");
 
     // send 503 over mqtt while disconnected should not change anything
     assertTrue(model.disconnectBoth2BothInput(mqttUri(TOPIC_BOTH_MQTT_RECEIVE)));
     sendDataForBoth("513", true);
-    checkData(2, "FromMqtt-112-M2M-ToMqtt",
+    checkData(initialNumberOfValues + 2, "FromMqtt-112-M2M-ToMqtt",
         "FromRest-212-R2R-ToRest",
         "FromMqtt-312-M2R-ToRest",
-        2, "FromRest-412-R2M-ToMqtt",
-        2, "512-B2M-ToMqtt",
+        initialNumberOfValues + 2, "FromRest-412-R2M-ToMqtt",
+        initialNumberOfValues + 2, "512-B2M-ToMqtt",
         "512-B2R-ToRest");
 
     // send 514 over rest while still connected should update
     sendDataForBoth("514", false);
-    checkData(2, "FromMqtt-112-M2M-ToMqtt",
+    checkData(initialNumberOfValues + 2, "FromMqtt-112-M2M-ToMqtt",
         "FromRest-212-R2R-ToRest",
         "FromMqtt-312-M2R-ToRest",
-        2, "FromRest-412-R2M-ToMqtt",
-        3, "514-B2M-ToMqtt",
+        initialNumberOfValues + 2, "FromRest-412-R2M-ToMqtt",
+        initialNumberOfValues + 3, "514-B2M-ToMqtt",
         "514-B2R-ToRest");
 
     // send 515 over rest while also disconnected should not change anything
     assertTrue(model.disconnectBoth2BothInput(restUri(PATH_BOTH_REST_RECEIVE, REST_PORT)));
     sendDataForBoth("515", false);
-    checkData(2, "FromMqtt-112-M2M-ToMqtt",
+    checkData(initialNumberOfValues + 2, "FromMqtt-112-M2M-ToMqtt",
         "FromRest-212-R2R-ToRest",
         "FromMqtt-312-M2R-ToRest",
-        2, "FromRest-412-R2M-ToMqtt",
-        3, "514-B2M-ToMqtt",
+        initialNumberOfValues + 2, "FromRest-412-R2M-ToMqtt",
+        initialNumberOfValues + 3, "514-B2M-ToMqtt",
         "514-B2R-ToRest");
 
     // send new values. value over rest while sender disconnected does not provide a value anymore
     assertTrue(model.disconnectRest2RestOutput(restUri(PATH_REST_2_REST_SEND, REST_PORT)));
     assertTrue(model.disconnectMqtt2RestOutput(restUri(PATH_MQTT_2_REST_SEND, REST_PORT)));
     sendData("113", "213", "313", "413");
-    checkData(3, "FromMqtt-113-M2M-ToMqtt",
+    checker.incNumberOfValues();
+    checkData(initialNumberOfValues + 3, "FromMqtt-113-M2M-ToMqtt",
         NOT_MAPPED,
         NOT_MAPPED,
-        3, "FromRest-413-R2M-ToMqtt",
-        3, "514-B2M-ToMqtt",
+        initialNumberOfValues + 3, "FromRest-413-R2M-ToMqtt",
+        initialNumberOfValues + 3, "514-B2M-ToMqtt",
         "514-B2R-ToRest");
   }
 
@@ -349,8 +269,8 @@ public class ViaTest extends AbstractMqttTest {
     }
   }
 
-  private void checkData(int numberOfMqtt2MqttValues, String mqtt2MqttValue, String rest2RestValue, String mqtt2RestValue, int numberOfRest2MqttValues, String rest2MqttValue, int numberOfBoth2MqttValues, String both2MqttValue, String both2RestValue) throws InterruptedException {
-    TestUtils.waitForMqtt();
+  private void checkData(int numberOfMqtt2MqttValues, String mqtt2MqttValue, String rest2RestValue, String mqtt2RestValue, int numberOfRest2MqttValues, String rest2MqttValue, int numberOfBoth2MqttValues, String both2MqttValue, String both2RestValue) {
+    checker.check();
     dataMqtt2Mqtt.assertEqualData(numberOfMqtt2MqttValues, mqtt2MqttValue);
     dataRest2Mqtt.assertEqualData(numberOfRest2MqttValues, rest2MqttValue);
     dataBoth2Mqtt.assertEqualData(numberOfBoth2MqttValues, both2MqttValue);
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java
index 5e26ba01360aaad05681c6ee3c045be0a6ca835d..c22207d92347ec7879a98b1cfb29ed88890405d8 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java
@@ -1,8 +1,8 @@
 package org.jastadd.ragconnect.tests.list;
 
 import org.jastadd.ragconnect.tests.AbstractMqttTest;
-import org.jastadd.ragconnect.tests.TestUtils;
 import org.jastadd.ragconnect.tests.TestUtils.IntList;
+import org.jastadd.ragconnect.tests.TestUtils.TestChecker;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 
@@ -55,12 +55,9 @@ public abstract class AbstractListTest extends AbstractMqttTest {
     int getID();
   }
 
-  AbstractListTest(String shortName) {
-    this.shortName = shortName;
-  }
-
   protected static final String TOPIC_A = "a";
   protected static final String TOPIC_SINGLE_A = "single-a";
+  protected TestChecker checker;
 
   protected TestWrapperReceiverRoot receiverRoot;
   protected ReceiverData data;
@@ -68,6 +65,12 @@ public abstract class AbstractListTest extends AbstractMqttTest {
 
   private final String shortName;
 
+  AbstractListTest(String shortName) {
+    this.shortName = shortName;
+    checker = new TestChecker();
+    this.checker.setActualNumberOfValues(() -> data.numberOfElements);
+  }
+
   @Test
   public void checkJacksonReference() {
     testJaddContainReferenceToJackson(
@@ -76,53 +79,50 @@ public abstract class AbstractListTest extends AbstractMqttTest {
   }
 
   @Override
-  protected void communicateSendInitialValue() throws InterruptedException, IOException {
+  protected void communicateSendInitialValue() throws IOException {
+    checker.incNumberOfValues();
     checkTree(1, list(), list(0), list(), list(0));
 
-    setInput(1);
-    checkTree(2, list(1), list(1), list(1), list(0, 1));
-
-    setInput(1);
-    checkTree(2, list(1), list(1), list(1), list(0, 1));
-
-    setInput(2);
-    checkTree(3, list(1, 2), list(2), list(1, 1, 2), list(0, 1, 2));
-
-    setInput(3);
-    checkTree(4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(0, 1, 2, 3));
-
-    disconnectReceive();
-    setInput(4);
-    checkTree(5, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(0, 1, 2, 3));
-
-    disconnectSend();
-    setInput(5);
-    checkTree(5, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(0, 1, 2, 3));
+    communicateBoth(1, 0);
   }
 
   @Override
-  protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException {
+  protected void communicateOnlyUpdatedValue() throws IOException {
     checkTree(0, list(), list(), list(), list());
 
+    communicateBoth(0, null);
+  }
+
+  private void communicateBoth(int initialNumberOfValues, Integer firstElementOfWithAddFromSingleA) throws IOException {
     setInput(1);
-    checkTree(1, list(1), list(1), list(1), list(1));
+    checker.incNumberOfValues();
+    checkTree(initialNumberOfValues + 1, list(1), list(1), list(1),
+            list(firstElementOfWithAddFromSingleA, 1));
 
     setInput(1);
-    checkTree(1, list(1), list(1), list(1), list(1));
+    checkTree(initialNumberOfValues + 1, list(1), list(1), list(1),
+            list(firstElementOfWithAddFromSingleA, 1));
 
     setInput(2);
-    checkTree(2, list(1, 2), list(2), list(1, 1, 2), list(1, 2));
+    checker.incNumberOfValues();
+    checkTree(initialNumberOfValues + 2, list(1, 2), list(2), list(1, 1, 2),
+            list(firstElementOfWithAddFromSingleA, 1, 2));
 
     setInput(3);
-    checkTree(3, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(1, 2, 3));
+    checker.incNumberOfValues();
+    checkTree(initialNumberOfValues + 3, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3),
+            list(firstElementOfWithAddFromSingleA, 1, 2, 3));
 
     disconnectReceive();
     setInput(4);
-    checkTree(4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(1, 2, 3));
+    checker.incNumberOfValues();
+    checkTree(initialNumberOfValues + 4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3),
+            list(firstElementOfWithAddFromSingleA, 1, 2, 3));
 
     disconnectSend();
     setInput(5);
-    checkTree(4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(1, 2, 3));
+    checkTree(initialNumberOfValues + 4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3),
+            list(firstElementOfWithAddFromSingleA, 1, 2, 3));
   }
 
   protected abstract void disconnectReceive() throws IOException;
@@ -131,13 +131,13 @@ public abstract class AbstractListTest extends AbstractMqttTest {
 
   protected abstract void setInput(int input);
 
-  private void checkTree(int expectedTransmissions, IntList normalA, IntList fromSingleA, IntList withAddA, IntList withAddFromSingleA) throws InterruptedException {
-    TestUtils.waitForMqtt();
+  private void checkTree(int expectedTransmissions, IntList normalA, IntList fromSingleA, IntList withAddA, IntList withAddFromSingleA) {
+    checker.check();
 
     assertEquals(expectedTransmissions, data.numberOfElements, "transmissions for normal");
     assertEquals(expectedTransmissions, dataSingle.numberOfElements, "transmissions for single");
 
-    checkList(normalA.toList(), receiverRoot.getNumA(), receiverRoot::getA, true);
+    checkList(normalA.toList(), receiverRoot.getNumA(), receiverRoot::getA);
     checkList(normalA.toList(), receiverRoot.getAList(), true);
     checkList(normalA.toList(), receiverRoot.getAs(), true);
 
@@ -151,15 +151,13 @@ public abstract class AbstractListTest extends AbstractMqttTest {
     checkList(withAddFromSingleA.toList(), receiverRoot.getWithAddFromSingleAs(), false);
   }
 
-  private void checkList(List<Integer> expectedList, int numChildren, Function<Integer, TestWrapperA> getA, boolean expectB) {
+  private void checkList(List<Integer> expectedList, int numChildren, Function<Integer, TestWrapperA> getA) {
     assertEquals(expectedList.size(), numChildren, "same list size");
     for (int index = 0; index < expectedList.size(); index++) {
       TestWrapperA a = getA.apply(index);
       assertEquals(expectedList.get(index), a.getID(), "correct ID for A");
-      if (expectB) {
-        assertEquals(1, a.getNumB(), "one B child");
-        assertEquals(expectedList.get(index) + 1, a.getB(0).getID(), "correct ID for B child");
-      }
+      assertEquals(1, a.getNumB(), "one B child");
+      assertEquals(expectedList.get(index) + 1, a.getB(0).getID(), "correct ID for B child");
     }
   }
 
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java
index 4ac0f55dc829a628c63c79409e69cf97f60985cf..9d38f1836f12c2eb95e22f44f9b21c1e0af7b013 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java
@@ -122,7 +122,8 @@ public class RelationTest extends AbstractMqttTest {
     assertTrue(handler.newConnection(TOPIC_WILDCARD, bytes -> data.numberOfValues += 1));
 
     checker = new TestChecker();
-    checker.setActualNumberOfValues(() -> data.numberOfValues).setCheckForString(TOPIC_MY_A,
+    checker.setActualNumberOfValues(() -> data.numberOfValues)
+            .setCheckForString(TOPIC_MY_A,
                     (name, expected) -> assertNullOrA(expected, receiverRoot.getFromMyA(), name))
             .setCheckForString(TOPIC_OPTIONAL_A,
                     (name, expected) -> assertNullOrA(expected, receiverRoot.getFromOptionalA(), name))
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java
index cdcb41c72e1af5b9b53f9afba3fd78eefbe06bd6..2cc90eff6205674a313b30c984a4b7f08c5cd082 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java
@@ -2,7 +2,6 @@ package org.jastadd.ragconnect.tests.singleList;
 
 import org.jastadd.ragconnect.tests.AbstractMqttTest;
 import org.jastadd.ragconnect.tests.TestUtils;
-import org.jastadd.ragconnect.tests.TestUtils.IntList;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import singleList.ast.MqttHandler;
@@ -27,6 +26,7 @@ import static org.junit.jupiter.api.Assertions.*;
 @Tag("SingleList")
 public abstract class AbstractSingleListTest extends AbstractMqttTest {
 
+  private final TestChecker checker;
   protected MqttHandler handler;
 
   public interface TestWrapperJastAddList<T> extends Iterable<T> {
@@ -86,6 +86,8 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest {
 
   AbstractSingleListTest(String shortName) {
     this.shortName = shortName;
+    this.checker = new TestChecker();
+    this.checker.setActualNumberOfValues(() -> data.numberOfElements);
   }
 
   protected static final String TOPIC_A_1 = "a/first";
@@ -173,88 +175,99 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest {
 
   @Override
   protected void communicateSendInitialValue() throws InterruptedException, IOException {
-    checkTree(5, list(1, 2, 3, 4, 0), list(4, 3, 2, 1, 0), // normal: (normal / wildcard)
-                                     list(4, 3, 2, 1, 0), list(4, 3, 2, 1, 0)); // withAdd: (normal / wildcard)
+    checker.addToNumberOfValues(5);
+    checkTree(list(1, 2, 3, 4, 0), list(4, 3, 2, 1, 0), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0), list(4, 3, 2, 1, 0)); // withAdd: (normal / wildcard)
 
     // A1 will be 2 (1+1, previously 1)
     setInput(1, 1);
-    checkTree(6, list(2, 2, 3, 4, 0), list(4, 3, 2, 2, 0), // normal: (normal / wildcard)
-                                     list(4, 3, 2, 1, 0, 2), list(4, 3, 2, 1, 0, 2)); // withAdd: (normal / wildcard)
+    checker.incNumberOfValues();
+    checkTree(list(2, 2, 3, 4, 0), list(4, 3, 2, 2, 0), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2), list(4, 3, 2, 1, 0, 2)); // withAdd: (normal / wildcard)
 
     // A1 should stay at 2
     setInput(1, 1);
-    checkTree(6, list(2, 2, 3, 4, 0), list(4, 3, 2, 2, 0), // normal: (normal / wildcard)
-                                     list(4, 3, 2, 1, 0, 2), list(4, 3, 2, 1, 0, 2)); // withAdd: (normal / wildcard)
+    checkTree(list(2, 2, 3, 4, 0), list(4, 3, 2, 2, 0), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2), list(4, 3, 2, 1, 0, 2)); // withAdd: (normal / wildcard)
 
     // A1 will be 3 (2+1, previously 2)
     setInput(1, 2);
-    checkTree(7, list(3, 2, 3, 4, 0), list(4, 3, 2, 3, 0), // normal: (normal / wildcard)
-                                     list(4, 3, 2, 1, 0, 2, 3), list(4, 3, 2, 1, 0, 2, 3)); // withAdd: (normal / wildcard)
+    checker.incNumberOfValues();
+    checkTree(list(3, 2, 3, 4, 0), list(4, 3, 2, 3, 0), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2, 3), list(4, 3, 2, 1, 0, 2, 3)); // withAdd: (normal / wildcard)
 
     // InOut will be 5 (previously 0)
     setInput(5, 5);
-    checkTree(8, list(3, 2, 3, 4, 5), list(4, 3, 2, 3, 5), // normal: (normal / wildcard)
-                                     list(4, 3, 2, 1, 0, 2, 3, 5), list(4, 3, 2, 1, 0, 2, 3, 5)); // withAdd: (normal / wildcard)
+    checker.incNumberOfValues();
+    checkTree(list(3, 2, 3, 4, 5), list(4, 3, 2, 3, 5), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2, 3, 5), list(4, 3, 2, 1, 0, 2, 3, 5)); // withAdd: (normal / wildcard)
 
     // A3 will be 7 (4+3, previously 3)
     setInput(3, 4);
-    checkTree(9, list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard)
-                                     list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard)
+    checker.incNumberOfValues();
+    checkTree(list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard)
 
-    // A2 will be send, but not received
+    // A2 will be sent, but not received
     disconnectReceive();
     setInput(2, 5);
-    checkTree(10, list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard)
-        list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard)
+    checker.incNumberOfValues();
+    checkTree(list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard)
 
-    // A2 will not be send
+    // A2 will not be sent
     disconnectSend();
     setInput(2, 7);
-    checkTree(10, list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard)
-        list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard)
+    checkTree(list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard)
+            list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard)
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException {
-    checkTree(0, list(0, 0, 0, 0, 0), list(), // normal
-                                     list(), list()); // withAdd
+    checkTree(list(0, 0, 0, 0, 0), list(), // normal
+            list(), list()); // withAdd
 
     // A1 will be 2 (1+1, previously 1)
     setInput(1, 1);
-    checkTree(1, list(2, 0, 0, 0, 0), list(2), // normal
-                                     list(2), list(2)); // withAdd
+    checker.incNumberOfValues();
+    checkTree(list(2, 0, 0, 0, 0), list(2), // normal
+            list(2), list(2)); // withAdd
 
     // A1 should stay at 2
     setInput(1, 1);
-    checkTree(1, list(2, 0, 0, 0, 0), list(2), // normal
-                                     list(2), list(2)); // withAdd
+    checkTree(list(2, 0, 0, 0, 0), list(2), // normal
+            list(2), list(2)); // withAdd
 
     // A1 will be 3 (2+1, previously 2)
     setInput(1, 2);
-    checkTree(2, list(3, 0, 0, 0, 0), list(3), // normal
-                                     list(2, 3), list(2, 3)); // withAdd
+    checker.incNumberOfValues();
+    checkTree(list(3, 0, 0, 0, 0), list(3), // normal
+            list(2, 3), list(2, 3)); // withAdd
 
     // InOut will be 5 (previously 0)
     setInput(5, 5);
-    checkTree(3, list(3, 0, 0, 0, 5), list(3, 5), // normal
-                                     list(2, 3, 5), list(2, 3, 5)); // withAdd
+    checker.incNumberOfValues();
+    checkTree(list(3, 0, 0, 0, 5), list(3, 5), // normal
+            list(2, 3, 5), list(2, 3, 5)); // withAdd
 
     // A3 will be 7 (4+3, previously 3)
     setInput(3, 4);
-    checkTree(4, list(3, 0, 7, 0, 5), list(3,5,7), // normal
-                                     list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd
+    checker.incNumberOfValues();
+    checkTree(list(3, 0, 7, 0, 5), list(3, 5, 7), // normal
+            list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd
 
-    // A2 will be send, but not received
+    // A2 will be sent, but not received
     disconnectReceive();
     setInput(2, 5);
-    checkTree(5, list(3, 0, 7, 0, 5), list(3,5,7), // normal
-        list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd
+    checker.incNumberOfValues();
+    checkTree(list(3, 0, 7, 0, 5), list(3, 5, 7), // normal
+            list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd
 
-    // A2 will not be send
+    // A2 will not be sent
     disconnectSend();
     setInput(2, 7);
-    checkTree(5, list(3, 0, 7, 0, 5), list(3,5,7), // normal
-        list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd
+    checkTree(list(3, 0, 7, 0, 5), list(3, 5, 7), // normal
+            list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd
   }
 
   protected void disconnectReceive() throws IOException {
@@ -296,9 +309,8 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest {
     assertEquals(input + index, actualComputedValue, "ID value of single A");
   }
 
-  private void checkTree(int expectedTransmissions, IntList normalA, IntList usingWildcardA, IntList withAddA, IntList usingWildcardWithAddA) throws InterruptedException {
-    TestUtils.waitForMqtt();
-    assertEquals(expectedTransmissions, data.numberOfElements, "transmissions for any A");
+  private void checkTree(IntList normalA, IntList usingWildcardA, IntList withAddA, IntList usingWildcardWithAddA) {
+    checker.check();
 
     checkList(normalA.toList(), receiverRoot.getNumA(), receiverRoot::getA);
     checkList(normalA.toList(), receiverRoot.getAList());
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java
index 34846a3a425d0254797b4502f754d28ddac06f8c..f84cd7946c25a25bebd46f9291b323f20c16377a 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java
@@ -2,8 +2,8 @@ package org.jastadd.ragconnect.tests.singleListVariant;
 
 import org.assertj.core.api.Assertions;
 import org.jastadd.ragconnect.tests.AbstractMqttTest;
-import org.jastadd.ragconnect.tests.TestUtils;
 import org.jastadd.ragconnect.tests.TestUtils.IntList;
+import org.jastadd.ragconnect.tests.TestUtils.TestChecker;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 
@@ -28,6 +28,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("SingleList")
 public abstract class AbstractSingleListVariantTest extends AbstractMqttTest {
 
+  private final TestChecker checker;
+
   public interface TestWrapperJastAddList<T> extends Iterable<T> {
     int getNumChild();
   }
@@ -155,6 +157,8 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest {
 
   AbstractSingleListVariantTest(String shortName) {
     this.shortName = shortName;
+    this.checker = new TestChecker();
+    this.checker.setActualNumberOfValues(() -> data.numberOfElements);
   }
 
   protected static final String TOPIC_T_Empty = "t/Empty";
@@ -229,81 +233,92 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest {
   @Override
   protected void communicateSendInitialValue() throws IOException, InterruptedException {
     // transmissions: 8 * 1 = 8
-    checkTree(8, list(-0), list(0), list(-0));
+    checker.addToNumberOfValues(8);
+    checkTree(list(-0), list(0), list(-0));
 
     setInput(1);
     // transmissions: 8 + 8 = 16
-    checkTree(16, list(-1), list(0, 1), list(-0, -1));
+    checker.addToNumberOfValues(8);
+    checkTree(list(-1), list(0, 1), list(-0, -1));
 
     setInput(1);
     // transmissions: 16
-    checkTree(16, list(-1), list(0, 1), list(-0, -1));
+    checkTree(list(-1), list(0, 1), list(-0, -1));
 
     setShouldSetOptAndList(true);
     // transmissions: 16 + 3 = 19
-    checkTree(19, list(1), list(0, 1), list(-0, -1, 1));
+    checker.addToNumberOfValues(3);
+    checkTree(list(1), list(0, 1), list(-0, -1, 1));
 
     setShouldSetOptAndList(true);
     // transmissions: 19
-    checkTree(19, list(1), list(0, 1), list(-0, -1, 1));
+    checkTree(list(1), list(0, 1), list(-0, -1, 1));
 
     setInput(2);
     // transmissions: 19 + 8 = 27
-    checkTree(27, list(2), list(0, 1, 2), list(-0, -1, 1, 2));
+    checker.addToNumberOfValues(8);
+    checkTree(list(2), list(0, 1, 2), list(-0, -1, 1, 2));
 
     setInput(5);
     // transmissions: 27 + 8 = 35
-    checkTree(35, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5));
+    checker.addToNumberOfValues(8);
+    checkTree(list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5));
 
     disconnectReceive();
     setInput(6); // does not affect receive
     // transmissions: 35 + 8 = 43
-    checkTree(43, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5));
+    checker.addToNumberOfValues(8);
+    checkTree(list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5));
 
     disconnectSend();
     setInput(7); // not sent
     // transmissions: 43
-    checkTree(43, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5));
+    checkTree(list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5));
   }
 
   @Override
   protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException {
     // transmissions: 0
-    checkTree(0, list(), list(), list());
+    checkTree(list(), list(), list());
 
     setInput(1);
     // transmissions: 8 * 1 = 0
-    checkTree(8, list(-1), list(1), list(-1));
+    checker.addToNumberOfValues(8);
+    checkTree(list(-1), list(1), list(-1));
 
     setInput(1);
     // transmissions: 8
-    checkTree(8, list(-1), list(1), list(-1));
+    checkTree(list(-1), list(1), list(-1));
 
     setShouldSetOptAndList(true);
     // transmissions: 8 + 3 = 11
-    checkTree(11, list(1), list(1), list(-1, 1));
+    checker.addToNumberOfValues(3);
+    checkTree(list(1), list(1), list(-1, 1));
 
     setShouldSetOptAndList(true);
     // transmissions: 11
-    checkTree(11, list(1), list(1), list(-1, 1));
+    checkTree(list(1), list(1), list(-1, 1));
 
     setInput(2);
     // transmissions: 11 + 8 = 19
-    checkTree(19, list(2), list(1, 2), list(-1, 1, 2));
+    checker.addToNumberOfValues(8);
+    checkTree(list(2), list(1, 2), list(-1, 1, 2));
 
     setInput(5);
     // transmissions: 19 + 8 = 27
-    checkTree(27, list(5), list(1, 2, 5), list(-1, 1, 2, 5));
+    checker.addToNumberOfValues(8);
+    checkTree(list(5), list(1, 2, 5), list(-1, 1, 2, 5));
 
     disconnectReceive();
     setInput(6); // does not affect receive
     // transmissions: 27 + 8 = 35
-    checkTree(35, list(5), list(1, 2, 5), list(-1, 1, 2, 5));
+    checker.addToNumberOfValues(8);
+    checkTree(list(5), list(1, 2, 5), list(-1, 1, 2, 5));
 
     disconnectSend();
     setInput(7); // not sent
     // transmissions: 35
-    checkTree(35, list(5), list(1, 2, 5), list(-1, 1, 2, 5));
+    checkTree(list(5), list(1, 2, 5), list(-1, 1, 2, 5));
   }
 
   private void disconnectReceive() throws IOException {
@@ -357,20 +372,15 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest {
    * Check against expected lists of IDs.
    * If an ID is negative, do not check Opts and Lists, but use absolute value for comparison.
    * The tests starts with ID 0 and does not use opts and lists at this point, so checking with > 0 is used.
-   * @param expectedTransmissions            expected number of total transmissions
    * @param expectedList                     ids for unnamed and named endpoints without add
    * @param expectedWithAddList              ids for endpoints with add, but not those with opts and lists
    *                                         (only positive numbers can/need to be passed)
    * @param expectedWithAddListForOptAndList ids for endpoints with add and with opts and lists
-   * @throws InterruptedException if interrupted in TestUtils.waitForMqtt
    */
-  private void checkTree(int expectedTransmissions,
-                         IntList expectedList,
+  private void checkTree(IntList expectedList,
                          IntList expectedWithAddList,
-                         IntList expectedWithAddListForOptAndList)
-      throws InterruptedException {
-    TestUtils.waitForMqtt();
-    assertEquals(expectedTransmissions, data.numberOfElements, "transmissions for any element");
+                         IntList expectedWithAddListForOptAndList) {
+    checker.check();
 
     // check unnamed
     checkList(expectedList, receiverRoot.getT_EmptyList(), (e, n) -> {});
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalTest.java
similarity index 83%
rename from ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java
rename to ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalTest.java
index 0bd6bcf7218b32f4737716380a5239d178ecdbce..c1b37cc695a1470896da2e19b18a296bcb008ec7 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalTest.java
@@ -1,9 +1,11 @@
 package org.jastadd.ragconnect.tests.singleListVariant;
 
 import org.jastadd.ragconnect.tests.TestUtils;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Tag;
-import singleListVariantInc.ast.*;
+import singleListVariantInc.ast.MqttHandler;
+import singleListVariantInc.ast.ReceiverRoot;
+import singleListVariantInc.ast.Root;
+import singleListVariantInc.ast.SenderRoot;
 
 import java.io.IOException;
 import java.util.concurrent.TimeUnit;
@@ -17,13 +19,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
  * @author rschoene - Initial contribution
  */
 @Tag("Incremental")
-@Disabled("Fails indeterministically")
-public class SingleListVariantIncrementalVariantTest extends AbstractSingleListVariantTest {
+public class SingleListVariantIncrementalTest extends AbstractSingleListVariantTest {
 
   private Root model;
   private MqttHandler handler;
 
-  SingleListVariantIncrementalVariantTest() {
+  SingleListVariantIncrementalTest() {
     super("singleListVariantInc");
   }
 
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualTest.java
similarity index 95%
rename from ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java
rename to ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualTest.java
index 6ae0e75b5d2d35375baf508ce7af8044158370bc..60238c8a1ca3c1301d08512cc469ce78bdc13e18 100644
--- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualTest.java
@@ -14,12 +14,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
  *
  * @author rschoene - Initial contribution
  */
-public class SingleListVariantManualVariantTest extends AbstractSingleListVariantTest {
+public class SingleListVariantManualTest extends AbstractSingleListVariantTest {
 
   private Root model;
   private MqttHandler handler;
 
-  SingleListVariantManualVariantTest() {
+  SingleListVariantManualTest() {
     super("singleListVariant");
   }
 
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/AbstractTokenValueSendTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/AbstractTokenValueSendTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcc3e8a9b60c7aebefb0884418959e6ea194c158
--- /dev/null
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/AbstractTokenValueSendTest.java
@@ -0,0 +1,224 @@
+package org.jastadd.ragconnect.tests.tokenValue;
+
+import org.jastadd.ragconnect.tests.AbstractMqttTest;
+import org.jastadd.ragconnect.tests.TestUtils;
+import org.jastadd.ragconnect.tests.TestUtils.TestChecker;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import tokenValueSend.ast.MqttHandler;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.concurrent.TimeUnit;
+
+import static org.jastadd.ragconnect.tests.TestUtils.mqttUri;
+import static org.jastadd.ragconnect.tests.TestUtils.testJaddContainReferenceToJackson;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Test case "tokenValueSend".
+ *
+ * @author rschoene - Initial contribution
+ */
+public abstract class AbstractTokenValueSendTest extends AbstractMqttTest {
+  protected static final String TOPIC_SEND_ONE = "one/value/out";
+
+  protected static final String TOPIC_RECEIVE_TWO = "two/value/in";
+  protected static final String TOPIC_SEND_TWO = "two/value/out";
+
+  protected static final String TOPIC_RECEIVE_THREE_VALUE = "three/value/in";
+  protected static final String TOPIC_SEND_THREE_VALUE = "three/value/out";
+  protected static final String TOPIC_SEND_THREE_OTHER = "three/other/out";
+
+  protected static final String INITIAL_VALUE = "Start";
+
+  protected MqttHandler handler;
+  protected TestChecker checker;
+
+  protected final String shortName;
+
+  private ReceiverData dataOne;
+  private ReceiverData dataTwo;
+  private ReceiverData dataThree;
+  private ReceiverData dataThreeOther;
+
+  AbstractTokenValueSendTest(String shortName) {
+    this.shortName = shortName;
+    this.checker = new TestChecker();
+    this.checker.setActualNumberOfValues(() -> dataOne.numberOfStringValues + dataTwo.numberOfStringValues +
+            dataThree.numberOfStringValues + dataThreeOther.numberOfStringValues);
+  }
+
+  @Test
+  public void checkJacksonReference() {
+    testJaddContainReferenceToJackson(
+            Paths.get("src", "test",
+                    "02-after-ragconnect", shortName, "RagConnect.jadd"), false);
+  }
+
+  @Override
+  protected void setupReceiverAndConnect() throws IOException {
+    handler = new MqttHandler().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost());
+    assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS));
+
+    dataOne = new ReceiverData();
+    dataTwo = new ReceiverData();
+    dataThree = new ReceiverData();
+    dataThreeOther = new ReceiverData();
+
+    handler.newConnection(TOPIC_SEND_ONE, bytes -> {
+      dataOne.numberOfStringValues += 1;
+      dataOne.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
+    });
+    handler.newConnection(TOPIC_SEND_TWO, bytes -> {
+      dataTwo.numberOfStringValues += 1;
+      dataTwo.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
+    });
+
+    handler.newConnection(TOPIC_SEND_THREE_VALUE, bytes -> {
+      dataThree.numberOfStringValues += 1;
+      dataThree.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
+    });
+    handler.newConnection(TOPIC_SEND_THREE_OTHER, bytes -> {
+      dataThreeOther.numberOfStringValues += 1;
+      dataThreeOther.lastStringValue = TestUtils.DefaultMappings.BytesToString(bytes);
+    });
+
+    connectModel();
+  }
+
+  protected abstract void connectModel() throws IOException;
+
+  @Override
+  protected void communicateSendInitialValue() throws InterruptedException, IOException {
+    // check initial value
+    checker.addToNumberOfValues(4);
+    checkData(1, "Start-Post",
+        1, "Start-Post",
+        1, "Start-Post",
+        1, "Start-T-Post");
+
+    communicateBoth(1, "Start-Post");
+  }
+
+  @Override
+  protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException {
+    // check initial value
+    checkData(0, null,
+            0, null,
+            0, null,
+            0, null);
+
+    communicateBoth(0, null);
+  }
+
+  private void communicateBoth(int initialNumberOfValues, String initialLastOneStringValue) throws IOException {
+    // send new value
+    sendData("210", "310");
+    checker.addToNumberOfValues(3);
+    checkData(initialNumberOfValues, initialLastOneStringValue,
+        initialNumberOfValues + 1, "Pre-210-Post",
+        initialNumberOfValues + 1, "Pre-310-Post",
+        initialNumberOfValues + 1, "Pre-310-T-Post");
+
+    // set new value
+    setData("111", "211", "311");
+    checker.addToNumberOfValues(4);
+    checkData(initialNumberOfValues + 1, "111-Post",
+        initialNumberOfValues + 2, "211-Post",
+        initialNumberOfValues + 2, "311-Post",
+        initialNumberOfValues + 2, "311-T-Post");
+
+    // send the same values (will not be sent again)
+    setData("111", "211", "311");
+    checkData(initialNumberOfValues + 1, "111-Post",
+        initialNumberOfValues + 2, "211-Post",
+        initialNumberOfValues + 2, "311-Post",
+        initialNumberOfValues + 2, "311-T-Post");
+
+    // send values with prefixes imitating receiving
+    checker.addToNumberOfValues(4);
+    setData("112", "Pre-212", "Pre-312");
+    checkData(initialNumberOfValues + 2, "112-Post",
+        initialNumberOfValues + 3, "Pre-212-Post",
+        initialNumberOfValues + 3, "Pre-312-Post",
+        initialNumberOfValues + 3, "Pre-312-T-Post");
+
+    // send the same values (will not be sent again, because previously prefixed)
+    sendData("212", "312");
+    checkData(initialNumberOfValues + 2, "112-Post",
+        initialNumberOfValues + 3, "Pre-212-Post",
+        initialNumberOfValues + 3, "Pre-312-Post",
+        initialNumberOfValues + 3, "Pre-312-T-Post");
+
+    // new values for two and three, but two will not send updated value
+    assertTrue(disconnect("two", "SendValue", mqttUri(TOPIC_SEND_TWO)));
+    sendData("213", "313");
+    checker.addToNumberOfValues(2);
+    checkData(initialNumberOfValues + 2, "112-Post",
+        initialNumberOfValues + 3, "Pre-212-Post",
+        initialNumberOfValues + 4, "Pre-313-Post",
+        initialNumberOfValues + 4, "Pre-313-T-Post");
+    assertEquals("Pre-213", valueOfReceiveAndSend());
+
+    // can not disconnect again, and also not for different topic
+    assertFalse(disconnect("two", "SendValue", mqttUri(TOPIC_SEND_TWO)));
+    assertFalse(disconnect("two", "SendValue", mqttUri(TOPIC_RECEIVE_TWO)));
+
+    // new values for two and three, but two will neither receive nor send updated value
+    assertTrue(disconnect("two", "ReceiveValue", mqttUri(TOPIC_RECEIVE_TWO)));
+    sendData("214", "314");
+    checker.addToNumberOfValues(2);
+    checkData(initialNumberOfValues + 2, "112-Post",
+        initialNumberOfValues + 3, "Pre-212-Post",
+        initialNumberOfValues + 5, "Pre-314-Post",
+        initialNumberOfValues + 5, "Pre-314-T-Post");
+    assertEquals("Pre-213", valueOfReceiveAndSend());
+
+    // new values for three, but it will not receive updated value, and, thus, not send it either
+    assertTrue(disconnect("three", "ReceiveValue", mqttUri(TOPIC_RECEIVE_THREE_VALUE)));
+    sendData("214", "315");
+    checkData(initialNumberOfValues + 2, "112-Post",
+        initialNumberOfValues + 3, "Pre-212-Post",
+        initialNumberOfValues + 5, "Pre-314-Post",
+        initialNumberOfValues + 5, "Pre-314-T-Post");
+    assertEquals("Pre-213", valueOfReceiveAndSend());
+
+    // disconnect send is possible
+    assertTrue(disconnect("three", "SendValue", mqttUri(TOPIC_SEND_THREE_VALUE)));
+  }
+
+  protected abstract boolean disconnect(String objectIdentifier, String targetIdentifier, String topic) throws IOException;
+
+  protected abstract String valueOfReceiveAndSend();
+
+  private void sendData(String inputTwo, String inputThree) {
+    publisher.publish(TOPIC_RECEIVE_TWO, inputTwo.getBytes());
+    publisher.publish(TOPIC_RECEIVE_THREE_VALUE, inputThree.getBytes());
+  }
+
+  protected abstract void setData(String inputOne, String inputTwo, String inputThree);
+
+  private void checkData(int numberOfOneValues, String lastOneStringValue,
+                         int numberOfTwoValues, String lastTwoStringValue,
+                         int numberOfThreeValues, String lastThreeStringValue,
+                         int numberOfOtherValues, String lastOtherStringValue
+  ) {
+    checker.check();
+    dataOne.assertEqualData(numberOfOneValues, lastOneStringValue);
+    dataTwo.assertEqualData(numberOfTwoValues, lastTwoStringValue);
+    dataThree.assertEqualData(numberOfThreeValues, lastThreeStringValue);
+    dataThreeOther.assertEqualData(numberOfOtherValues, lastOtherStringValue);
+  }
+
+  private static class ReceiverData {
+    String lastStringValue;
+    int numberOfStringValues = 0;
+
+    public void assertEqualData(int expectedNumberOfValues, String expectedLastValue) {
+      assertEquals(expectedNumberOfValues, this.numberOfStringValues);
+      assertEquals(expectedLastValue, this.lastStringValue);
+    }
+  }
+
+}
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/TokenValueSendIncrementalTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/TokenValueSendIncrementalTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9676b9ca75daba39580da7eb848f6d088f5073e8
--- /dev/null
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/TokenValueSendIncrementalTest.java
@@ -0,0 +1,93 @@
+package org.jastadd.ragconnect.tests.tokenValue;
+
+import org.junit.jupiter.api.Tag;
+import tokenValueSendInc.ast.*;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import static org.jastadd.ragconnect.tests.TestUtils.mqttUri;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test case "tokenValueSend incremental".
+ *
+ * @author rschoene - Initial contribution
+ */
+@Tag("Incremental")
+public class TokenValueSendIncrementalTest extends AbstractTokenValueSendTest {
+
+  private A model;
+
+  TokenValueSendIncrementalTest() {
+    super("tokenValueSend");
+  }
+
+  @Override
+  protected void createModel() {
+    // Setting value for Input without dependencies does not trigger any updates
+    model = new A();
+
+    model.setOnlySend(new OnlySend().setValue(INITIAL_VALUE));
+    model.setReceiveAndSend(new ReceiveAndSend().setValue(INITIAL_VALUE));
+    model.setReceiveSendAndDepend(new ReceiveSendAndDepend().setValue(INITIAL_VALUE));
+  }
+
+
+  @Override
+  public void closeConnections() {
+    if (handler != null) {
+      handler.close();
+    }
+    if (model != null) {
+      model.ragconnectCloseConnections();
+    }
+  }
+
+  @Override
+  protected void connectModel() throws IOException {
+    model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
+
+    // no dependencies
+
+    assertTrue(model.getOnlySend().connectValue(mqttUri(TOPIC_SEND_ONE), isWriteCurrentValue()));
+    assertTrue(model.getReceiveAndSend().connectValue(mqttUri(TOPIC_RECEIVE_TWO)));
+    assertTrue(model.getReceiveAndSend().connectValue(mqttUri(TOPIC_SEND_TWO), isWriteCurrentValue()));
+    assertTrue(model.getReceiveSendAndDepend().connectValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE)));
+    assertTrue(model.getReceiveSendAndDepend().connectValue(mqttUri(TOPIC_SEND_THREE_VALUE), isWriteCurrentValue()));
+    assertTrue(model.getReceiveSendAndDepend().connectOtherOutput(mqttUri(TOPIC_SEND_THREE_OTHER), isWriteCurrentValue()));
+  }
+
+  @Override
+  protected boolean disconnect(String objectIdentifier, String targetIdentifier, String topic) throws IOException {
+    switch (objectIdentifier) {
+      case "two":
+        ReceiveAndSend receiveAndSend = model.getReceiveAndSend();
+        switch (targetIdentifier) {
+          case "SendValue": return receiveAndSend.disconnectSendValue(topic);
+          case "ReceiveValue": return receiveAndSend.disconnectReceiveValue(topic);
+        }
+        break;
+      case "three":
+        ReceiveSendAndDepend receiveSendAndDepend = model.getReceiveSendAndDepend();
+        switch (targetIdentifier) {
+          case "SendValue": return receiveSendAndDepend.disconnectSendValue(topic);
+          case "ReceiveValue": return receiveSendAndDepend.disconnectReceiveValue(topic);
+        }
+        break;
+    }
+    throw new IllegalArgumentException(objectIdentifier + " on " + targetIdentifier + " for " + topic);
+  }
+
+  @Override
+  protected String valueOfReceiveAndSend() {
+    return model.getReceiveAndSend().getValue();
+  }
+
+  @Override
+  protected void setData(String inputOne, String inputTwo, String inputThree) {
+    model.getOnlySend().setValue(inputOne);
+    model.getReceiveAndSend().setValue(inputTwo);
+    model.getReceiveSendAndDepend().setValue(inputThree);
+  }
+}
diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/TokenValueSendManualTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/TokenValueSendManualTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a24f8a8be3358118978019bb25d26e2a276a897b
--- /dev/null
+++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tokenValue/TokenValueSendManualTest.java
@@ -0,0 +1,91 @@
+package org.jastadd.ragconnect.tests.tokenValue;
+
+import tokenValueSend.ast.*;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import static org.jastadd.ragconnect.tests.TestUtils.mqttUri;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test case "tokenValueSend manual".
+ *
+ * @author rschoene - Initial contribution
+ */
+public class TokenValueSendManualTest extends AbstractTokenValueSendTest {
+
+  private A model;
+
+  TokenValueSendManualTest() {
+    super("tokenValueSend");
+  }
+
+  @Override
+  protected void createModel() {
+    // Setting value for Input without dependencies does not trigger any updates
+    model = new A();
+
+    model.setOnlySend(new OnlySend().setValue(INITIAL_VALUE));
+    model.setReceiveAndSend(new ReceiveAndSend().setValue(INITIAL_VALUE));
+    model.setReceiveSendAndDepend(new ReceiveSendAndDepend().setValue(INITIAL_VALUE));
+  }
+
+
+  @Override
+  public void closeConnections() {
+    if (handler != null) {
+      handler.close();
+    }
+    if (model != null) {
+      model.ragconnectCloseConnections();
+    }
+  }
+
+  @Override
+  protected void connectModel() throws IOException {
+    model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS);
+
+    model.getReceiveSendAndDepend().addDependency1(model.getReceiveSendAndDepend());
+
+    assertTrue(model.getOnlySend().connectValue(mqttUri(TOPIC_SEND_ONE), isWriteCurrentValue()));
+    assertTrue(model.getReceiveAndSend().connectValue(mqttUri(TOPIC_RECEIVE_TWO)));
+    assertTrue(model.getReceiveAndSend().connectValue(mqttUri(TOPIC_SEND_TWO), isWriteCurrentValue()));
+    assertTrue(model.getReceiveSendAndDepend().connectValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE)));
+    assertTrue(model.getReceiveSendAndDepend().connectValue(mqttUri(TOPIC_SEND_THREE_VALUE), isWriteCurrentValue()));
+    assertTrue(model.getReceiveSendAndDepend().connectOtherOutput(mqttUri(TOPIC_SEND_THREE_OTHER), isWriteCurrentValue()));
+  }
+
+  @Override
+  protected boolean disconnect(String objectIdentifier, String targetIdentifier, String topic) throws IOException {
+    switch (objectIdentifier) {
+      case "two":
+        ReceiveAndSend receiveAndSend = model.getReceiveAndSend();
+        switch (targetIdentifier) {
+          case "SendValue": return receiveAndSend.disconnectSendValue(topic);
+          case "ReceiveValue": return receiveAndSend.disconnectReceiveValue(topic);
+        }
+        break;
+      case "three":
+        ReceiveSendAndDepend receiveSendAndDepend = model.getReceiveSendAndDepend();
+        switch (targetIdentifier) {
+          case "SendValue": return receiveSendAndDepend.disconnectSendValue(topic);
+          case "ReceiveValue": return receiveSendAndDepend.disconnectReceiveValue(topic);
+        }
+        break;
+    }
+    throw new IllegalArgumentException(objectIdentifier + " on " + targetIdentifier + " for " + topic);
+  }
+
+  @Override
+  protected String valueOfReceiveAndSend() {
+    return model.getReceiveAndSend().getValue();
+  }
+
+  @Override
+  protected void setData(String inputOne, String inputTwo, String inputThree) {
+    model.getOnlySend().setValue(inputOne);
+    model.getReceiveAndSend().setValue(inputTwo);
+    model.getReceiveSendAndDepend().setValue(inputThree);
+  }
+}