diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2248c4cdd7a79cde8755e5c5a387de93549cc36a..e671445c259e623375d06a00fc11df81da84d1a5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -52,7 +52,9 @@ stages:
         -DWALBERLA_STL_BOUNDS_CHECKS=$WALBERLA_STL_BOUNDS_CHECKS
       - cmake . -LA
       - make -j $NUM_BUILD_CORES -l $NUM_CORES
-      - ctest -LE $CTEST_EXCLUDE_LABELS -C $CMAKE_BUILD_TYPE --output-on-failure -j $NUM_CORES
+      - ctest -LE $CTEST_EXCLUDE_LABELS -C $CMAKE_BUILD_TYPE --output-on-failure -j $NUM_CORES -T Test
+   after_script:
+      - python3 cmake/ctest2junit.py build > report.xml
    tags:
       - docker
    variables:
@@ -67,6 +69,12 @@ stages:
       WALBERLA_BUILD_WITH_METIS: "ON"
       WALBERLA_BUILD_WITH_PARMETIS: "ON"
       WALBERLA_ENABLE_GUI: "OFF"
+   artifacts:
+      when: always
+      reports:
+         junit:
+            - report.xml
+            - python/report.xml
 
 
 ###############################################################################
@@ -83,8 +91,7 @@ intel_19_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -109,8 +116,7 @@ intel_19_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -133,8 +139,7 @@ intel_19_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -152,8 +157,7 @@ intel_19_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -175,8 +179,7 @@ intel_19_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -196,8 +199,7 @@ intel_19_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -230,8 +232,7 @@ gcc_7_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -255,8 +256,7 @@ gcc_7_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -278,8 +278,7 @@ gcc_7_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -300,8 +299,7 @@ gcc_7_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -327,8 +325,7 @@ gcc_7_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -351,8 +348,7 @@ gcc_7_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -387,8 +383,7 @@ gcc_8_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -412,8 +407,7 @@ gcc_8_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -435,8 +429,7 @@ gcc_8_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -457,8 +450,7 @@ gcc_8_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -483,8 +475,7 @@ gcc_8_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -507,8 +498,7 @@ gcc_8_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -547,8 +537,7 @@ gcc_9_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -570,8 +559,7 @@ gcc_9_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -591,8 +579,7 @@ gcc_9_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -611,8 +598,7 @@ gcc_9_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -635,8 +621,7 @@ gcc_9_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -657,8 +642,7 @@ gcc_9_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -694,8 +678,7 @@ gcc_10_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -717,8 +700,7 @@ gcc_10_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -739,8 +721,7 @@ gcc_10_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -755,8 +736,7 @@ gcc_10_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -775,8 +755,7 @@ gcc_10_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -793,8 +772,7 @@ gcc_10_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
    variables:
       WALBERLA_BUILD_WITH_CUDA: "OFF"
@@ -822,8 +800,7 @@ clang_6.0_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -847,8 +824,7 @@ clang_6.0_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -870,8 +846,7 @@ clang_6.0_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -892,8 +867,7 @@ clang_6.0_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -918,8 +892,7 @@ clang_6.0_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -942,8 +915,7 @@ clang_6.0_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -978,8 +950,7 @@ clang_7.0_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1003,8 +974,7 @@ clang_7.0_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1026,8 +996,7 @@ clang_7.0_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1048,8 +1017,7 @@ clang_7.0_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1074,8 +1042,7 @@ clang_7.0_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1098,8 +1065,7 @@ clang_7.0_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1138,8 +1104,7 @@ clang_8.0_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1163,8 +1128,7 @@ clang_8.0_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1186,8 +1150,7 @@ clang_8.0_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1208,8 +1171,7 @@ clang_8.0_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1234,8 +1196,7 @@ clang_8.0_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1258,8 +1219,7 @@ clang_8.0_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1298,8 +1258,7 @@ clang_9.0_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1323,8 +1282,7 @@ clang_9.0_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1346,8 +1304,7 @@ clang_9.0_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1368,8 +1325,7 @@ clang_9.0_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1394,8 +1350,7 @@ clang_9.0_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1418,8 +1373,7 @@ clang_9.0_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1458,8 +1412,7 @@ clang_10.0_serial:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1483,8 +1436,7 @@ clang_10.0_mpionly:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1506,8 +1458,7 @@ clang_10.0_hybrid:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1524,8 +1475,7 @@ clang_10.0_serial_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1546,8 +1496,7 @@ clang_10.0_mpionly_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1566,8 +1515,7 @@ clang_10.0_hybrid_dbg:
    before_script:
       - pip3 install lbmpy jinja2
       - cd python
-      - python3 -m unittest discover pystencils_walberla/
-      - python3 -m unittest discover lbmpy_walberla/
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
       - cd ..
       - CC=gcc CXX=g++ pip3 install pycuda
    variables:
@@ -1757,7 +1705,9 @@ coverage:
       - cd build
       - cmake -LA -DWALBERLA_BUILD_TESTS=ON -DWALBERLA_BUILD_BENCHMARKS=ON -DWALBERLA_BUILD_TUTORIALS=ON -DWALBERLA_BUILD_WITH_MPI=$WALBERLA_BUILD_WITH_MPI -DWALBERLA_BUILD_WITH_OPENMP=$WALBERLA_BUILD_WITH_OPENMP -DWALBERLA_DOUBLE_ACCURACY=$WALBERLA_DOUBLE_ACCURACY -DWARNING_ERROR=ON -G "$CMAKE_GENERATOR" -DCMAKE_DISABLE_FIND_PACKAGE_Boost=TRUE ..
       - MSBuild.exe walberla.sln /property:Configuration=$BUILD_CONFIGURATION /verbosity:minimal /maxcpucount:4
-      - ctest -LE $CTEST_EXCLUDE_LABELS -C $BUILD_CONFIGURATION --output-on-failure -j 4
+      - ctest -LE $CTEST_EXCLUDE_LABELS -C $BUILD_CONFIGURATION --output-on-failure -j 4 -T Test
+   after_script:
+      - python3 cmake/ctest2junit.py build > report.xml
    variables:
       CMAKE_GENERATOR: "Visual Studio 15 2017 Win64"
       BUILD_CONFIGURATION: "Release"
@@ -1765,6 +1715,12 @@ coverage:
       WALBERLA_BUILD_WITH_MPI: "ON"
       WALBERLA_BUILD_WITH_OPENMP: "ON"
       WALBERLA_DOUBLE_ACCURACY: "ON"
+   artifacts:
+      when: always
+      reports:
+         junit:
+            - report.xml
+            - python/report.xml
 
 
 
@@ -1937,9 +1893,22 @@ msvc-14.2_mpionly:
       - cmake .. -DWALBERLA_BUILD_TESTS=ON -DWALBERLA_BUILD_BENCHMARKS=ON -DWALBERLA_BUILD_TUTORIALS=ON -DWALBERLA_BUILD_TOOLS=ON -DWALBERLA_BUILD_WITH_MPI=$WALBERLA_BUILD_WITH_MPI -DWALBERLA_BUILD_WITH_PYTHON=$WALBERLA_BUILD_WITH_PYTHON -DWALBERLA_BUILD_WITH_OPENMP=$WALBERLA_BUILD_WITH_OPENMP -DWALBERLA_BUILD_WITH_CUDA=$WALBERLA_BUILD_WITH_CUDA -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE -DWARNING_ERROR=ON
       - cmake . -LA
       - make -j $NUM_BUILD_CORES -l $NUM_CORES
-      - ctest -LE "$CTEST_EXCLUDE_LABELS|cuda" -C $CMAKE_BUILD_TYPE --output-on-failure -j $NUM_CORES
+      - ctest -LE "$CTEST_EXCLUDE_LABELS|cuda" -C $CMAKE_BUILD_TYPE --output-on-failure -j $NUM_CORES -T Test
+   before_script:
+      - pip3 install --user lbmpy jinja2 pytest-cov lxml
+      - cd python
+      - python3 -m pytest --junitxml=report.xml pystencils_walberla lbmpy_walberla
+      - cd ..
+   after_script:
+      - python3 cmake/ctest2junit.py build > report.xml
    tags:
       - mac
+   artifacts:
+      when: always
+      reports:
+         junit:
+            - report.xml
+            - python/report.xml
 
 mac_Serial_Dbg:
    <<: *mac_build_definition
diff --git a/cmake/ctest2junit.py b/cmake/ctest2junit.py
new file mode 100755
index 0000000000000000000000000000000000000000..9474cd2604f7132717fba3b0f451d8bb7c4d78b5
--- /dev/null
+++ b/cmake/ctest2junit.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python3
+# This file is from https://github.com/scikit-build/scikit-ci-addons/tree/master/anyci
+# under Apache 2.0 license.
+
+import os
+import sys
+
+from lxml import etree
+
+
+def process(build_dir):
+
+    tag_file = build_dir + "/Testing/TAG"
+    if not os.path.exists(tag_file):
+        raise RuntimeError("Missing tag file %s" % tag_file)
+
+    with open(build_dir + "/Testing/TAG", 'r') as tag:
+        dir_name = tag.readline().strip()
+
+    test_xml = build_dir + "/Testing/" + dir_name + "/Test.xml"
+    if not os.path.exists(test_xml):
+        raise RuntimeError("Couldn't find %s" % test_xml)
+
+    xsl = """<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="xml" indent="yes"/>
+
+    <xsl:template match="/Site">
+        <testsuite>
+            <xsl:variable name="BuildName"><xsl:value-of select="@BuildName"/></xsl:variable>
+            <xsl:variable name="BuildStamp"><xsl:value-of select="@BuildStamp"/></xsl:variable>
+            <xsl:variable name="Name"><xsl:value-of select="@Name"/></xsl:variable>
+            <xsl:variable name="Generator"><xsl:value-of select="@Generator"/></xsl:variable>
+            <xsl:variable name="CompilerName"><xsl:value-of select="@CompilerName"/></xsl:variable>
+            <xsl:variable name="OSName"><xsl:value-of select="@OSName"/></xsl:variable>
+            <xsl:variable name="Hostname"><xsl:value-of select="@Hostname"/></xsl:variable>
+            <xsl:variable name="OSRelease"><xsl:value-of select="@OSRelease"/></xsl:variable>
+            <xsl:variable name="OSVersion"><xsl:value-of select="@OSVersion"/></xsl:variable>
+            <xsl:variable name="OSPlatform"><xsl:value-of select="@OSPlatform"/></xsl:variable>
+            <xsl:variable name="Is64Bits"><xsl:value-of select="@Is64Bits"/></xsl:variable>
+            <xsl:variable name="VendorString"><xsl:value-of select="@VendorString"/></xsl:variable>
+            <xsl:variable name="VendorID"><xsl:value-of select="@VendorID"/></xsl:variable>
+            <xsl:variable name="FamilyID"><xsl:value-of select="@FamilyID"/></xsl:variable>
+            <xsl:variable name="ModelID"><xsl:value-of select="@ModelID"/></xsl:variable>
+            <xsl:variable name="ProcessorCacheSize"><xsl:value-of select="@ProcessorCacheSize"/></xsl:variable>
+            <xsl:variable name="NumberOfLogicalCPU"><xsl:value-of select="@NumberOfLogicalCPU"/></xsl:variable>
+            <xsl:variable name="NumberOfPhysicalCPU"><xsl:value-of select="@NumberOfPhysicalCPU"/></xsl:variable>
+            <xsl:variable name="TotalVirtualMemory"><xsl:value-of select="@TotalVirtualMemory"/></xsl:variable>
+            <xsl:variable name="TotalPhysicalMemory"><xsl:value-of select="@TotalPhysicalMemory"/></xsl:variable>
+            <xsl:variable name="LogicalProcessorsPerPhysical">
+                <xsl:value-of select="@LogicalProcessorsPerPhysical"/>
+            </xsl:variable>
+            <xsl:variable name="ProcessorClockFrequency">
+                <xsl:value-of select="@ProcessorClockFrequency"/>
+            </xsl:variable>
+            <properties>
+                <property name="BuildName" value="{$BuildName}" />
+                <property name="BuildStamp" value="{$BuildStamp}" />
+                <property name="Name" value="{$Name}" />
+                <property name="Generator" value="{$Generator}" />
+                <property name="CompilerName" value="{$CompilerName}" />
+                <property name="OSName" value="{$OSName}" />
+                <property name="Hostname" value="{$Hostname}" />
+                <property name="OSRelease" value="{$OSRelease}" />
+                <property name="OSVersion" value="{$OSVersion}" />
+                <property name="OSPlatform" value="{$OSPlatform}" />
+                <property name="Is64Bits" value="{$Is64Bits}" />
+                <property name="VendorString" value="{$VendorString}" />
+                <property name="VendorID" value="{$VendorID}" />
+                <property name="FamilyID" value="{$FamilyID}" />
+                <property name="ModelID" value="{$ModelID}" />
+                <property name="ProcessorCacheSize" value="{$ProcessorCacheSize}" />
+                <property name="NumberOfLogicalCPU" value="{$NumberOfLogicalCPU}" />
+                <property name="NumberOfPhysicalCPU" value="{$NumberOfPhysicalCPU}" />
+                <property name="TotalVirtualMemory" value="{$TotalVirtualMemory}" />
+                <property name="TotalPhysicalMemory" value="{$TotalPhysicalMemory}" />
+                <property name="LogicalProcessorsPerPhysical" value="{$LogicalProcessorsPerPhysical}" />
+                <property name="ProcessorClockFrequency" value="{$ProcessorClockFrequency}" />
+            </properties>
+            <xsl:apply-templates select="Testing/Test"/>
+
+            <system-out>
+                BuildName: <xsl:value-of select="$BuildName" />
+                BuildStamp: <xsl:value-of select="$BuildStamp" />
+                Name: <xsl:value-of select="$Name" />
+                Generator: <xsl:value-of select="$Generator" />
+                CompilerName: <xsl:value-of select="$CompilerName" />
+                OSName: <xsl:value-of select="$OSName" />
+                Hostname: <xsl:value-of select="$Hostname" />
+                OSRelease: <xsl:value-of select="$OSRelease" />
+                OSVersion: <xsl:value-of select="$OSVersion" />
+                OSPlatform: <xsl:value-of select="$OSPlatform" />
+                Is64Bits: <xsl:value-of select="$Is64Bits" />
+                VendorString: <xsl:value-of select="$VendorString" />
+                VendorID: <xsl:value-of select="$VendorID" />
+                FamilyID: <xsl:value-of select="$FamilyID" />
+                ModelID: <xsl:value-of select="$ModelID" />
+                ProcessorCacheSize: <xsl:value-of select="$ProcessorCacheSize" />
+                NumberOfLogicalCPU: <xsl:value-of select="$NumberOfLogicalCPU" />
+                NumberOfPhysicalCPU: <xsl:value-of select="$NumberOfPhysicalCPU" />
+                TotalVirtualMemory: <xsl:value-of select="$TotalVirtualMemory" />
+                TotalPhysicalMemory: <xsl:value-of select="$TotalPhysicalMemory" />
+                LogicalProcessorsPerPhysical: <xsl:value-of select="$LogicalProcessorsPerPhysical" />
+                ProcessorClockFrequency: <xsl:value-of select="$ProcessorClockFrequency" />
+            </system-out>
+        </testsuite>
+    </xsl:template>
+
+    <xsl:template match="Testing/Test">
+        <xsl:variable name="testcasename"><xsl:value-of select= "Name"/></xsl:variable>
+        <xsl:variable name="exectime">
+            <xsl:for-each select="Results/NamedMeasurement">
+                <xsl:if test="@name = 'Execution Time'">
+                    <xsl:value-of select="."/>
+                </xsl:if>
+            </xsl:for-each>
+        </xsl:variable>
+
+        <testcase name="{$testcasename}" classname="TestSuite" time="{$exectime}">
+            <xsl:if test="@Status = 'passed'">
+            </xsl:if>
+            <xsl:if test="@Status = 'failed'">
+                <xsl:variable name="failtype">
+                    <xsl:for-each select="Results/NamedMeasurement">
+                        <xsl:if test="@name = 'Exit Code'">
+                            <xsl:value-of select="."/>
+                        </xsl:if>
+                    </xsl:for-each>
+                </xsl:variable>
+                <xsl:variable name="failcode">
+                    <xsl:for-each select="Results/NamedMeasurement">
+                        <xsl:if test="@name = 'Exit Value'">
+                            <xsl:value-of select="."/>
+                        </xsl:if>
+                    </xsl:for-each>
+                </xsl:variable>
+                <error message="{$failtype} ({$failcode})">
+                    <xsl:value-of select="Results/Measurement/Value/text()" />
+                </error>
+            </xsl:if>
+            <xsl:if test="@Status = 'notrun'">
+                <skipped><xsl:value-of select="Results/Measurement/Value/text()" /></skipped>
+            </xsl:if>
+        </testcase>
+    </xsl:template>
+
+</xsl:stylesheet>
+"""
+
+    xml_doc = etree.parse(test_xml)
+    xslt_root = etree.XML(xsl)
+    transform = etree.XSLT(xslt_root)
+    result_tree = transform(xml_doc)
+    return result_tree
+
+
+if __name__ == "__main__":
+    print(process(sys.argv[1]))