diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt
index a6346665975c27a9b9545ba87728c25a8bef2747..b2d84016e92485ae8aa074c1d79f1de86172b6c6 100644
--- a/test/io/CMakeLists.txt
+++ b/test/io/CMakeLists.txt
@@ -1,5 +1,6 @@
+add_subdirectory(container)
 add_subdirectory(gnuplotinterface)
 add_subdirectory(gridmanager)
-add_subdirectory(container)
-add_subdirectory(vtk)
+add_subdirectory(inputdata)
 add_subdirectory(rasterimagereader)
+add_subdirectory(vtk)
diff --git a/test/io/inputdata/CMakeLists.txt b/test/io/inputdata/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ecf567d10832f99a1ae87a8ce813cdb2f0c6d037
--- /dev/null
+++ b/test/io/inputdata/CMakeLists.txt
@@ -0,0 +1,2 @@
+dune_symlink_to_source_files(FILES config.ini coordinates.txt mydata.xml numbers.txt)
+dumux_add_test(SOURCES test_io_data_input.cc LABELS unit io)
diff --git a/test/io/inputdata/config.ini b/test/io/inputdata/config.ini
new file mode 100644
index 0000000000000000000000000000000000000000..691d2cefa42baae1d636ca451d19c74739a3276e
--- /dev/null
+++ b/test/io/inputdata/config.ini
@@ -0,0 +1,6 @@
+[MyData]
+InjectionRate = 0.1 0.2 0.3 0.4
+BoundaryFlags = 3 4 5 6
+
+[Problem]
+Gravity = false
diff --git a/test/io/inputdata/coordinates.txt b/test/io/inputdata/coordinates.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4360a73c26fa9daf6d10d0c18a16e0f608859bac
--- /dev/null
+++ b/test/io/inputdata/coordinates.txt
@@ -0,0 +1,4 @@
+0.1 0.1 0.054
+0.2 0.1 0.054
+0.3 0.2 0.054
+0.4 0.1 0.454
diff --git a/test/io/inputdata/mydata.xml b/test/io/inputdata/mydata.xml
new file mode 100644
index 0000000000000000000000000000000000000000..64e9b2cff391d87b68c4ed2ba079fa7c2765bab1
--- /dev/null
+++ b/test/io/inputdata/mydata.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- Simple custom data file -->
+<InputData>
+  <!-- Injection rates are in kg/s -->
+  <InjectionRates>
+  0.1 0.2 0.3 0.4
+  </InjectionRates>
+
+  <!-- BoundaryTypes: -1: no boundary, 0: Dirichlet, 1: Noflow, 2: Infiltration, 3: Outflow -->
+  <BoundaryTypes>
+  0 -1 -1 2
+  </BoundaryTypes>
+</InputData>
diff --git a/test/io/inputdata/numbers.txt b/test/io/inputdata/numbers.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c23c5da710efc48cf929a2358caa3f4a3a54d59e
--- /dev/null
+++ b/test/io/inputdata/numbers.txt
@@ -0,0 +1,4 @@
+0.1
+0.2
+0.3
+0.4
diff --git a/test/io/inputdata/test_io_data_input.cc b/test/io/inputdata/test_io_data_input.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0be56eb9c3c8193e662653d83e0a29c869fc32d5
--- /dev/null
+++ b/test/io/inputdata/test_io_data_input.cc
@@ -0,0 +1,112 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 3 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Test and example of how to read custom user data in Dumux
+ */
+#include <config.h>
+
+#include <algorithm>
+#include <vector>
+#include <iostream>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/parametertreeparser.hh>
+
+#include <dumux/io/container.hh>
+#include <dumux/io/xml/tinyxml2.h>
+
+////////////////////////
+// the main function
+////////////////////////
+int main()
+{
+    using namespace Dumux;
+
+    {
+        std::cout << "Reading a simple list of numbers into a vector\n";
+        std::cout << "-- Read numbers.txt: \n";
+
+        // the file extension ".txt" is arbitrary, works with any other extension or none
+        const auto numbers = readFileToContainer<std::vector<double>>("numbers.txt");
+
+        std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<double>(std::cout, ", "));
+        std::cout << "\n" << std::endl;
+    }
+
+    {
+        std::cout << "Reading a three-column list of numbers into a vector\n";
+        std::cout << "-- Read coordinates.txt: \n";
+
+        // the file extension ".txt" is arbitrary, works with any other extension or none
+        const auto coordinates = readFileToContainer<std::vector<Dune::FieldVector<double, 3>>>("coordinates.txt");
+
+        std::copy(coordinates.begin(), coordinates.end(), std::ostream_iterator<Dune::FieldVector<double, 3>>(std::cout, ", "));
+        std::cout << "\n" << std::endl;
+    }
+
+    {
+        std::cout << "Reading a key-value ini-style file into a Dune::ParameterTree\n";
+        std::cout << "-- Read config.ini: \n";
+
+        Dune::ParameterTree config;
+        // the file extension ".ini" is arbitrary, works with any other extension or none
+        Dune::ParameterTreeParser::readINITree("config.ini", config);
+
+        config.report();
+        std::cout << "\n";
+
+        std::cout << "-- Parsing MyData.InjectionRate into a vector: \n";
+
+        const auto injectionRates = config.get<std::vector<double>>("MyData.InjectionRate");
+
+        std::copy(injectionRates.begin(), injectionRates.end(), std::ostream_iterator<double>(std::cout, " "));
+        std::cout << "\n" << std::endl;
+    }
+
+    {
+        std::cout << "Reading a XML-formatted data using tiny xml\n";
+
+        tinyxml2::XMLDocument xmlData;
+        // the file extension ".xml" is arbitrary, works with any other extension or none
+        const auto returnCode = xmlData.LoadFile("mydata.xml");
+        if (returnCode != tinyxml2::XML_SUCCESS)
+            DUNE_THROW(Dune::IOError, "Couldn't open XML file.");
+        const tinyxml2::XMLElement* inputData = xmlData.FirstChildElement("InputData");
+
+        std::cout << "-- Read InjectionRates field: \n";
+
+        std::stringstream injectionData(inputData->FirstChildElement("InjectionRates")->GetText());
+        const auto injectionRates = readStreamToContainer<std::vector<double>>(injectionData);
+
+        std::copy(injectionRates.begin(), injectionRates.end(), std::ostream_iterator<double>(std::cout, " "));
+        std::cout << "\n";
+
+        std::cout << "-- Read BoundaryTypes field: \n";
+
+        std::stringstream boundaryData(inputData->FirstChildElement("BoundaryTypes")->GetText());
+        const auto boundaryTypes = readStreamToContainer<std::vector<int>>(boundaryData);
+
+        std::copy(boundaryTypes.begin(), boundaryTypes.end(), std::ostream_iterator<int>(std::cout, " "));
+        std::cout << "\n" << std::endl;
+    }
+
+    return 0;
+}