diff --git a/tests/executables_src/testConfigReader.cc b/tests/executables_src/testConfigReader.cc
index 0ce87261ecb78f103a784aa9913e0476b26f592e..9ed4201047c89fe76b0036cc951cccd994a73821 100644
--- a/tests/executables_src/testConfigReader.cc
+++ b/tests/executables_src/testConfigReader.cc
@@ -47,11 +47,23 @@ struct TestModule : ctk::ApplicationModule {
   ctk::ArrayPushInput<int32_t> intArray{this, "intArray", "MV/m", 10, "Desc"};
   ctk::ArrayPushInput<std::string> stringArray{this, "stringArray", "", 8, "Desc"};
 
-  ctk::ScalarPushInput<int16_t> m1_var16{this, "module1/var16", "MV/m", "Desc"};
-  ctk::ScalarPushInput<uint16_t> m1_var16u{this, "module1/var16u", "MV/m", "Desc"};
-  ctk::ScalarPushInput<int32_t> m1_var32{this, "module1/var32", "MV/m", "Desc"};
-  ctk::ScalarPushInput<uint32_t> m1_var32u{this, "module1/var32u", "MV/m", "Desc"};
-  ctk::ScalarPushInput<uint32_t> m1_sub_var32u{this, "module1/submodule/var32u", "MV/m", "Desc"};
+  struct Module1 : ctk::VariableGroup {
+    using ctk::VariableGroup::VariableGroup;
+    ctk::ScalarPushInput<int16_t> var16{this, "var16", "MV/m", "Desc"};
+    ctk::ScalarPushInput<uint16_t> var16u{this, "var16u", "MV/m", "Desc"};
+    ctk::ScalarPushInput<int32_t> var32{this, "var32", "MV/m", "Desc"};
+    ctk::ScalarPushInput<uint32_t> var32u{this, "var32u", "MV/m", "Desc"};
+    ctk::ScalarPushInput<std::string> varString{this, "varString", "MV/m", "Desc"};
+
+    struct SubModule : ctk::VariableGroup {
+      using ctk::VariableGroup::VariableGroup;
+      ctk::ScalarPushInput<uint32_t> var32u{this, "var32u", "MV/m", "Desc"};
+      ctk::ArrayPushInput<int32_t> intArray{this, "intArray", "MV/m", 10, "Desc"};
+      ctk::ArrayPushInput<std::string> stringArray{this, "stringArray", "", 8, "Desc"};
+    } submodule{this, "submodule", ""};
+
+  } module1{this, "module1", ""};
+
 
   std::atomic<bool> done{false};
 
@@ -75,11 +87,17 @@ struct TestModule : ctk::ApplicationModule {
     BOOST_CHECK_EQUAL(stringArray.getNElements(), 8);
     for(size_t i = 0; i < 8; ++i) BOOST_CHECK_EQUAL(stringArray[i], "Hallo" + std::to_string(i + 1));
 
-    BOOST_CHECK_EQUAL((int16_t)m1_var16, -567);
-    BOOST_CHECK_EQUAL((uint16_t)m1_var16u, 678);
-    BOOST_CHECK_EQUAL((int32_t)m1_var32, -345678);
-    BOOST_CHECK_EQUAL((uint32_t)m1_var32u, 234567);
-    BOOST_CHECK_EQUAL((uint32_t)m1_sub_var32u, 234567);
+    BOOST_CHECK_EQUAL((int16_t)module1.var16, -567);
+    BOOST_CHECK_EQUAL((uint16_t)module1.var16u, 678);
+    BOOST_CHECK_EQUAL((int32_t)module1.var32, -345678);
+    BOOST_CHECK_EQUAL((uint32_t)module1.var32u, 234567);
+    BOOST_CHECK_EQUAL((uint32_t)module1.submodule.var32u, 234567);
+
+    BOOST_CHECK_EQUAL(module1.submodule.intArray.getNElements(), 10);
+    for(size_t i = 0; i < 10; ++i) BOOST_CHECK_EQUAL(module1.submodule.intArray[i], 10 - i);
+
+    BOOST_CHECK_EQUAL(module1.submodule.stringArray.getNElements(), 8);
+    for(size_t i = 0; i < 8; ++i) BOOST_CHECK_EQUAL(module1.submodule.stringArray[i], "Hallo" + std::to_string(i + 1));
 
     // no further update shall be received
     usleep(1000000); // 1 second
@@ -96,6 +114,14 @@ struct TestModule : ctk::ApplicationModule {
     BOOST_CHECK(!varString.readNonBlocking());
     BOOST_CHECK(!intArray.readNonBlocking());
 
+    BOOST_CHECK(!module1.var16.readNonBlocking());
+    BOOST_CHECK(!module1.var16u.readNonBlocking());
+    BOOST_CHECK(!module1.var32.readNonBlocking());
+    BOOST_CHECK(!module1.var32u.readNonBlocking());
+    BOOST_CHECK(!module1.submodule.var32u.readNonBlocking());
+    BOOST_CHECK(!module1.submodule.intArray.readNonBlocking());
+    BOOST_CHECK(!module1.submodule.stringArray.readNonBlocking());
+
     // inform main thread that we are done
     done = true;
   }
@@ -177,6 +203,14 @@ BOOST_AUTO_TEST_CASE(testConfigReader) {
   BOOST_CHECK_EQUAL(app.config.get<uint32_t>("module1/var32u"), 234567);
   BOOST_CHECK_EQUAL(app.config.get<uint32_t>("module1/submodule/var32u"), 234567);
 
+  arrayValue = app.config.get<std::vector<int>>("module1/submodule/intArray");
+  BOOST_CHECK_EQUAL(arrayValue.size(), 10);
+  for(size_t i = 0; i < 10; ++i) BOOST_CHECK_EQUAL(arrayValue[i], 10 - i);
+
+  arrayValueString = app.config.get<std::vector<std::string>>("module1/submodule/stringArray");
+  BOOST_CHECK_EQUAL(arrayValueString.size(), 8);
+  for(size_t i = 0; i < 8; ++i) BOOST_CHECK_EQUAL(arrayValueString[i], "Hallo" + std::to_string(i + 1));
+
   app.config.connectTo(app.testModule);
 
   app.initialise();
diff --git a/tests/validConfig.xml b/tests/validConfig.xml
index 043cacb9b4216ee91e349496f257bac04d694b12..4ef2e224eceb69d0cbd896358fc0e108401b9775 100644
--- a/tests/validConfig.xml
+++ b/tests/validConfig.xml
@@ -38,13 +38,38 @@
     <value i="6" v="Hallo7"/>
     <value i="7" v="Hallo8"/>
   </variable>
-  <module name="emptymodule"/>
   <module name="module1">
+    <variable name="varString" type="string" value="My dear mister singing club!"/>
+    <variable name="var16" type="int16" value="-567"/>
     <variable name="var16u" type="uint16" value="678"/>
     <variable name="var32" type="int32" value="-345678"/>
     <variable name="var32u" type="uint32" value="234567"/>
     <module name="submodule">
       <variable name="var32u" type="uint32" value="234567"/>
+      <variable name="stringArray" type="string">
+        <value i="0" v="Hallo1"/>
+        <value i="1" v="Hallo2"/>
+        <value i="2" v="Hallo3"/>
+        <value i="3" v="Hallo4"/>
+        <value i="4" v="Hallo5"/>
+        <value i="5" v="Hallo6"/>
+        <value i="6" v="Hallo7"/>
+        <value i="7" v="Hallo8"/>
+      </variable>
+      <variable name="intArray" type="int32">
+        <!-- Values are intentionally out-of-order -->
+        <value i="0" v="10"/>
+        <value i="1" v="9"/>
+        <value i="2" v="8"/>
+        <value i="7" v="3"/>
+        <value i="8" v="2"/>
+        <value i="9" v="1"/>
+        <value i="3" v="7"/>
+        <value i="4" v="6"/>
+        <!-- Just a random comment -->
+        <value i="5" v="5"/>
+        <value i="6" v="4"/>
+      </variable>
     </module>
   </module>
   <!-- Just a random comment -->