diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ed37992de..ae760ea07 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -89,7 +89,7 @@ integration:
   dependencies:
     - build
   script:
-    - build/release/villas-node
+    - "build/release/villas-node || true"
   image: $DOCKER_REGISTRY/$DOCKER_IMAGE
   tags:
     - docker
diff --git a/Dockerfile b/Dockerfile
index 48ba1fe52..408766244 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -59,6 +59,13 @@ RUN dnf -y update && \
 	bison \
 	texinfo
 
+# Tools for coverage and profiling
+RUN dnf -y update && \
+    dnf -y install \
+        python-pip && \
+    pip install \
+        gcovr
+
 ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig
 ENV LD_LIBRARY_PATH /usr/local/lib
 
diff --git a/tests/Makefile.gcov.inc b/tests/Makefile.gcov.inc
new file mode 100644
index 000000000..c8833625e
--- /dev/null
+++ b/tests/Makefile.gcov.inc
@@ -0,0 +1,34 @@
+COVERAGE_TESTS = $(BUILDDIR)/testsuite
+COVERAGE_OBJS = $(LIB_OBJS) $(SRC_OBJS)
+
+GCDAS = $(COVERAGE_OBJS:.o=.gcda)
+GCNOS = $(COVERAGE_OBJS:.o=.gcno)
+
+GCOVR_OPTS = --exclude ^include --root . --sort-percentage --print-summary
+
+coverage: $(BUILDDIR)/coverage/index.html $(BUILDDIR)/coverage.xml $(BUILDDIR)/coverage.txt
+
+$(BUILDDIR)/coverage.txt:  $(addsuffix .gcdas,$(COVERAGE_TESTS)) | $$(dir $$@)
+	gcovr $(GCOVR_OPTS) -o $@
+
+$(BUILDDIR)/coverage.xml:  $(addsuffix .gcdas,$(COVERAGE_TESTS)) | $$(dir $$@)
+	gcovr $(GCOVR_OPTS) --xml --xml-pretty -o $@
+
+$(BUILDDIR)/coverage/index.html: $(addsuffix .gcdas,$(COVERAGE_TESTS)) | $$(dir $$@)
+	gcovr $(GCOVR_OPTS) --html --html-details -o $@
+
+# This is an intermediate target. It is used to run the test only once for all gcovr rules.
+%.gcdas: %
+	@echo "Delete previous coverage information"
+	rm -f $(GCDAS)
+	@echo "Run $< for collecting coverage information (.gcda)"
+	$^
+
+clean-coverage:
+	rm -rf $(BUILDDIR)/coverage $(BUILDDIR)/coverage.txt $(BUILDDIR)/coverage.xml
+	rm -f $(GCDAS)
+	
+install-coverage:
+
+.INTERMEDIATE: $(addsuffix .gcdas,$(COVERAGE_TESTS))
+.PHONY: coverage gcda clean-coverage install-coverage
\ No newline at end of file
diff --git a/tests/Makefile.inc b/tests/Makefile.inc
index 121ba1360..b701f5772 100644
--- a/tests/Makefile.inc
+++ b/tests/Makefile.inc
@@ -16,7 +16,7 @@ $(BUILDDIR)/testsuite: $(TEST_OBJS) | $(LIBS)
 	$(CC) $(TEST_LDFLAGS) $(TEST_LDLIBS) $^ -o $@
 
 ifdef COVERAGE
--include Makefile.gcov.inc
+-include tests/Makefile.gcov.inc
 endif
 
 # Tests are not installed