diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5541e950c5d6d847a015bfbd0ff7a9a59e285b84..1d8140805a3c437546d7a1e635722c6f6f06e1e7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,9 +8,12 @@ lint:
 test:
   script:
     - pacman -Syu --needed --noconfirm podman make
-    - make test
+    - make test BATS_EXTRA_ARGS='--formatter junit'
   tags:
     - vm
+  artifacts:
+    reports:
+      junit: coverage/bats-report.xml
 
 code-coverage:
   script:
diff --git a/Makefile b/Makefile
index 43aab9257ae1a0327c00222e0756be0b30aff43b..8737b1f18db5f95a42d8e974b685e400fc447a81 100644
--- a/Makefile
+++ b/Makefile
@@ -3,14 +3,17 @@ NETWORK:=none
 RUN_OPTIONS:=--rm --network=$(NETWORK) -v $(PWD):/dbscripts:ro --tmpfs=/tmp:exec -w /dbscripts/test
 CASES ?= cases
 JOBS ?= $(shell nproc)
-BATS_ARGS ?= --jobs $(JOBS) --verbose-run
+BATS_EXTRA_ARGS ?=
+BATS_ARGS ?= --jobs $(JOBS) $(BATS_EXTRA_ARGS) --verbose-run
 DOCKER ?= podman
 
 test-image:
 	$(DOCKER) build --pull -t $(IMAGE) test
 
 test: test-image
-	$(DOCKER) run $(RUN_OPTIONS) $(IMAGE) make CASES=$(CASES) BATS_ARGS="$(BATS_ARGS)" test
+	rm -rf coverage
+	mkdir -m 777 coverage
+	$(DOCKER) run $(RUN_OPTIONS) -v ${PWD}/coverage:/coverage -e COVERAGE_DIR=/coverage $(IMAGE) make CASES=$(CASES) BATS_ARGS="$(BATS_ARGS)" test
 
 test-coverage: test-image
 	rm -rf ${PWD}/coverage
diff --git a/test/Makefile b/test/Makefile
index f079ce5bae327d39f8ae06b8591c4e7abbae93d7..6799c0a0b2b7ae427da01a3b53cff63b51871e6f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,9 +1,12 @@
+SHELL=/bin/bash -o pipefail
+
 CASES ?= cases
 JOBS ?= $(shell nproc)
 BATS_ARGS ?= --jobs $(JOBS) --verbose-run
+COVERAGE_DIR ?= .
 
 test:
-	BUILDDIR=/build PATH=$(CURDIR)/../:$(CURDIR)/../cron-jobs/:$(PATH) bats $(BATS_ARGS) $(CASES)
+	BUILDDIR=/build PATH=$(CURDIR)/../:$(CURDIR)/../cron-jobs/:$(PATH) bats $(BATS_ARGS) $(CASES) | tee $(COVERAGE_DIR)/bats-report.xml
 
 test-coverage:
 	BUILDDIR=/build PATH=$(CURDIR)/../:$(CURDIR)/../cron-jobs/:$(PATH) kcov \