diff --git a/dune/grid/io/file/test/checkvtkfile.hh b/dune/grid/io/file/test/checkvtkfile.hh
index fb25763346d74a8106fbd5bcaf551f789ef85d2c..87e7e4f570e79c037008fabf5347f64bffe1af22 100644
--- a/dune/grid/io/file/test/checkvtkfile.hh
+++ b/dune/grid/io/file/test/checkvtkfile.hh
@@ -8,12 +8,18 @@
 #include <ios>
 #include <iostream>
 #include <ostream>
+#include <set>
 #include <sstream>
 #include <string>
 
 #include <sys/wait.h>
 
 #include <dune/common/exceptions.hh>
+#include <dune/common/test/testsuite.hh>
+
+namespace Dune {
+
+namespace Impl {
 
 // quote so the result can be used inside '...' in python
 // quotes not included in the result
@@ -83,9 +89,9 @@ inline bool is_suffix(const std::string &s, const std::string &suffix)
     s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;
 }
 
-inline int checkVTKFile(const std::string &name)
+inline bool havePythonVTK()
 {
-  static const bool havePythonVTK = [] {
+  static const bool result = [] {
     // This check is invoked only once, even in a multithreading environment,
     // since it is invoked in the initializer of a static variable.
     if(runPython("from vtk import *") == 0)
@@ -95,32 +101,78 @@ inline int checkVTKFile(const std::string &name)
               << "vtk can read the files we wrote." << std::endl;
     return false;
   } ();
-  if(!havePythonVTK)
-  {
-    std::cerr << "skip: " << name << std::endl;
-    return 77;
-  }
 
-  std::string reader;
-  if     (is_suffix(name, ".vtu"))  reader = "vtkXMLUnstructuredGridReader";
-  else if(is_suffix(name, ".pvtu")) reader = "vtkXMLPUnstructuredGridReader";
-  else if(is_suffix(name, ".vtp"))  reader = "vtkXMLPolyDataReader";
-  else if(is_suffix(name, ".pvtp")) reader = "vtkXMLPPolyDataReader";
-  else DUNE_THROW(Dune::NotImplemented,
-                  "Unknown vtk file extension: " << name);
-
-  std::cout << "Loading " << name << " using python vtk" << std::endl;
-  std::string pycode =
-    "from vtk import *;"
-    "import sys;"
-    "reader = "+reader+"();"
-    "reader.SetFileName('"+pyq(name)+"');"
-    "reader.Update();"
-    // check that the number of of cells is > 0
-    "sys.exit(not (reader.GetOutput().GetNumberOfCells() > 0));";
-  int result = runPython(pycode);
-  std::cout << (result == 0 ? "pass: " : "fail: ") << name << std::endl;
   return result;
 }
 
+inline std::string pythonVTKReader(const std::string& filename)
+{
+  if     (is_suffix(filename, ".vtu"))  return "vtkXMLUnstructuredGridReader";
+  else if(is_suffix(filename, ".pvtu")) return "vtkXMLPUnstructuredGridReader";
+  else if(is_suffix(filename, ".vtp"))  return "vtkXMLPolyDataReader";
+  else if(is_suffix(filename, ".pvtp")) return "vtkXMLPPolyDataReader";
+  else DUNE_THROW(Dune::NotImplemented,
+                  "Unknown vtk file extension: " << filename);
+}
+
+} /* namespace Impl */
+
+class VTKChecker
+{
+public:
+  void push(const std::string& file)
+    {
+      auto res = files_.insert(file);
+      if (not res.second) {
+        testSuite_.check(false, "VTKChecker")
+          << "'" << file << "' was added multiple times";
+      }
+    }
+
+  int check()
+    {
+      if (not Impl::havePythonVTK()) {
+        return 77;
+      }
+      else if (not files_.empty()) {
+        const int result = Impl::runPython(generatePythonCode());
+        testSuite_.check(result == 0);
+      }
+      return testSuite_.exit();
+    }
+
+  const TestSuite& testSuite() const
+    {
+      return testSuite_;
+    }
+
+private:
+  std::string generatePythonCode() const
+    {
+      std::stringstream code;
+
+      code << "from vtk import *\n"
+           << "import sys\n"
+           << "passed = True\n";
+
+      for (const auto& file : files_) {
+        code << "reader = " << Impl::pythonVTKReader(file) << "()\n"
+             << "reader.SetFileName('" << Impl::pyq(file) << "')\n"
+             << "reader.Update()\n"
+             << "if (not (reader.GetOutput().GetNumberOfCells() > 0)):\n"
+             << "    print('ERROR in {}'.format('" << Impl::pyq(file) << "'))\n"
+             << "    passed = False\n";
+      }
+
+      code << "sys.exit(0 if passed else 1)\n";
+
+      return code.str();
+    }
+
+  std::set< std::string > files_;
+  TestSuite testSuite_;
+};
+
+} /* namespace Dune */
+
 #endif // DUNE_GRID_IO_FILE_TEST_CHECKVTKFILE_HH
diff --git a/dune/grid/io/file/test/subsamplingvtktest.cc b/dune/grid/io/file/test/subsamplingvtktest.cc
index f59add0a3d87c1ce5e9e9d96038f62efe24979db..4c913721ae8d3d47dc42ac21dd279eed845cc2b2 100644
--- a/dune/grid/io/file/test/subsamplingvtktest.cc
+++ b/dune/grid/io/file/test/subsamplingvtktest.cc
@@ -84,7 +84,7 @@ struct Acc
 };
 
 template< class GridView >
-int doWrite( const GridView &gridView, bool coerceToSimplex)
+int doWrite( Dune::VTKChecker& vtkChecker, const std::string& gridViewName, const GridView &gridView, bool coerceToSimplex)
 {
   enum { dim = GridView :: dimension };
 
@@ -104,21 +104,21 @@ int doWrite( const GridView &gridView, bool coerceToSimplex)
   int result = 0;
   std::string name;
   std::ostringstream prefix;
-  prefix << "subsamplingvtktest-" << dim << "D-"
+  prefix << "subsamplingvtktest-" << dim << "D-" << gridViewName << "-"
          << (coerceToSimplex ? "simplex" : "natural");
   int rank = gridView.comm().rank();
 
   name = vtk.write(prefix.str() + "-ascii");
-  if(rank == 0) acc(result, checkVTKFile(name));
+  if(rank == 0) vtkChecker.push(name);
 
   name = vtk.write(prefix.str() + "-appendedraw", Dune::VTK::appendedraw);
-  if(rank == 0) acc(result, checkVTKFile(name));
+  if(rank == 0) vtkChecker.push(name);
 
   return result;
 }
 
 template<int dim>
-int vtkCheck(const std::array<int, dim>& elements,
+int vtkCheck(Dune::VTKChecker& vtkChecker, const std::array<int, dim>& elements,
               const Dune::FieldVector<double, dim>& upperRight)
 {
   Dune::YaspGrid<dim> g(upperRight, elements);
@@ -132,13 +132,13 @@ int vtkCheck(const std::array<int, dim>& elements,
 
   int result = 0;
 
-  acc(result, doWrite( g.leafGridView(), false));
-  acc(result, doWrite( g.levelGridView( 0 ), false));
-  acc(result, doWrite( g.levelGridView( g.maxLevel() ), false));
+  acc(result, doWrite( vtkChecker, "leafview", g.leafGridView(), false));
+  acc(result, doWrite( vtkChecker, "coarselevelview", g.levelGridView( 0 ), false));
+  acc(result, doWrite( vtkChecker, "finelevelview", g.levelGridView( g.maxLevel() ), false));
 
-  acc(result, doWrite( g.leafGridView(), true));
-  acc(result, doWrite( g.levelGridView( 0 ), true));
-  acc(result, doWrite( g.levelGridView( g.maxLevel() ), true));
+  acc(result, doWrite( vtkChecker, "leafview", g.leafGridView(), true));
+  acc(result, doWrite( vtkChecker, "coarselevelview", g.levelGridView( 0 ), true));
+  acc(result, doWrite( vtkChecker, "finelevelview", g.levelGridView( g.maxLevel() ), true));
 
   return result;
 }
@@ -156,9 +156,13 @@ int main(int argc, char **argv)
     int result = 0; // pass by default
     using Dune::make_array;
 
-    acc(result, vtkCheck<1>(make_array(5), {1.0}));
-    acc(result, vtkCheck<2>(make_array(5,5), {1.0, 2.0}));
-    acc(result, vtkCheck<3>(make_array(5,5,5), {1.0, 2.0, 3.0}));
+    Dune::VTKChecker vtkChecker;
+
+    acc(result, vtkCheck<1>(vtkChecker, make_array(5), {1.0}));
+    acc(result, vtkCheck<2>(vtkChecker, make_array(5,5), {1.0, 2.0}));
+    acc(result, vtkCheck<3>(vtkChecker, make_array(5,5,5), {1.0, 2.0, 3.0}));
+
+    acc(result, vtkChecker.check());
 
     mpiHelper.getCollectiveCommunication().allreduce<Acc>(&result, 1);
 
diff --git a/dune/grid/io/file/test/vtktest.cc b/dune/grid/io/file/test/vtktest.cc
index a5801feb1b47c6b3a83ea5fdb8e691bfadc17246..eb2f4c503ab3d87a383cfc906560d842d7deed7e 100644
--- a/dune/grid/io/file/test/vtktest.cc
+++ b/dune/grid/io/file/test/vtktest.cc
@@ -94,7 +94,7 @@ struct Acc
 };
 
 template< class GridView >
-int doWrite( const GridView &gridView, Dune :: VTK :: DataMode dm )
+int doWrite( Dune::VTKChecker& vtkChecker, const std::string& gridViewName, const GridView &gridView, Dune :: VTK :: DataMode dm )
 {
   enum { dim = GridView :: dimension };
 
@@ -113,27 +113,27 @@ int doWrite( const GridView &gridView, Dune :: VTK :: DataMode dm )
   int result = 0;
   std::string name;
   std::ostringstream prefix;
-  prefix << "vtktest-" << dim << "D-" << VTKDataMode(dm);
+  prefix << "vtktest-" << dim << "D-" << gridViewName << "-" << VTKDataMode(dm);
   int rank = gridView.comm().rank();
 
   name = vtk.write(prefix.str() + "-ascii");
-  if(rank == 0) acc(result, checkVTKFile(name));
+  if(rank == 0) vtkChecker.push(name);
 
   name = vtk.write(prefix.str() + "-base64", Dune::VTK::base64);
-  if(rank == 0) acc(result, checkVTKFile(name));
+  if(rank == 0) vtkChecker.push(name);
 
   name = vtk.write(prefix.str() + "-appendedraw", Dune::VTK::appendedraw);
-  if(rank == 0) acc(result, checkVTKFile(name));
+  if(rank == 0) vtkChecker.push(name);
 
   name = vtk.write(prefix.str() + "-appendedbase64",
                    Dune::VTK::appendedbase64);
-  if(rank == 0) acc(result, checkVTKFile(name));
+  if(rank == 0) vtkChecker.push(name);
 
   return result;
 }
 
 template<int dim>
-int vtkCheck(const std::array<int, dim>& elements,
+int vtkCheck(Dune::VTKChecker& vtkChecker, const std::array<int, dim>& elements,
               const Dune::FieldVector<double, dim>& upperRight)
 {
   Dune::YaspGrid<dim> g(upperRight, elements);
@@ -147,15 +147,15 @@ int vtkCheck(const std::array<int, dim>& elements,
 
   int result = 0;
 
-  acc(result, doWrite( g.leafGridView(), Dune::VTK::conforming ));
-  acc(result, doWrite( g.leafGridView(), Dune::VTK::nonconforming ));
-  acc(result, doWrite( g.levelGridView( 0 ),
+  acc(result, doWrite( vtkChecker, "leafview", g.leafGridView(), Dune::VTK::conforming ));
+  acc(result, doWrite( vtkChecker, "leafview", g.leafGridView(), Dune::VTK::nonconforming ));
+  acc(result, doWrite( vtkChecker, "coarselevelview", g.levelGridView( 0 ),
                        Dune::VTK::conforming ));
-  acc(result, doWrite( g.levelGridView( 0 ),
+  acc(result, doWrite( vtkChecker, "coarselevelview", g.levelGridView( 0 ),
                        Dune::VTK::nonconforming ));
-  acc(result, doWrite( g.levelGridView( g.maxLevel() ),
+  acc(result, doWrite( vtkChecker, "finelevelview", g.levelGridView( g.maxLevel() ),
                        Dune::VTK::conforming ));
-  acc(result, doWrite( g.levelGridView( g.maxLevel() ),
+  acc(result, doWrite( vtkChecker, "finelevelview", g.levelGridView( g.maxLevel() ),
                        Dune::VTK::nonconforming ));
 
   return result;
@@ -174,9 +174,13 @@ int main(int argc, char **argv)
     int result = 0; // pass by default
     using Dune::make_array;
 
-    acc(result, vtkCheck<1>(make_array(5), {1.0}));
-    acc(result, vtkCheck<2>(make_array(5,5), {1.0, 2.0}));
-    acc(result, vtkCheck<3>(make_array(5,5,5), {1.0, 2.0, 3.0}));
+    Dune::VTKChecker vtkChecker;
+
+    acc(result, vtkCheck<1>(vtkChecker, make_array(5), {1.0}));
+    acc(result, vtkCheck<2>(vtkChecker, make_array(5,5), {1.0, 2.0}));
+    acc(result, vtkCheck<3>(vtkChecker, make_array(5,5,5), {1.0, 2.0, 3.0}));
+
+    acc(result, vtkChecker.check());
 
     mpiHelper.getCollectiveCommunication().allreduce<Acc>(&result, 1);