diff --git a/.gitignore b/.gitignore
index 7d98dc6951e0c39af4ebec63b9ebec4e9871961c_LmdpdGlnbm9yZQ==..59fd71ccf469cb6db4d5d6dcfcb33553f1b77220_LmdpdGlnbm9yZQ== 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,5 @@
 spec/examples.txt
 
 .projections.json
+
+coverage/
diff --git a/Gemfile b/Gemfile
index 7d98dc6951e0c39af4ebec63b9ebec4e9871961c_R2VtZmlsZQ==..59fd71ccf469cb6db4d5d6dcfcb33553f1b77220_R2VtZmlsZQ== 100644
--- a/Gemfile
+++ b/Gemfile
@@ -52,4 +52,5 @@
   gem 'rspec_junit_formatter'
   gem 'pry'
   gem 'rspec-parameterized', require: false
+  gem 'simplecov-cobertura'
 end
diff --git a/Gemfile.lock b/Gemfile.lock
index 7d98dc6951e0c39af4ebec63b9ebec4e9871961c_R2VtZmlsZS5sb2Nr..59fd71ccf469cb6db4d5d6dcfcb33553f1b77220_R2VtZmlsZS5sb2Nr 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -134,6 +134,7 @@
     cookbook-omnifetch (0.9.1)
       mixlib-archive (>= 0.4, < 2.0)
     diff-lcs (1.3)
+    docile (1.4.0)
     docker-api (2.0.0)
       excon (>= 0.47.0)
       multi_json
@@ -347,6 +348,15 @@
     rubyntlm (0.6.2)
     rubyzip (2.3.0)
     semverse (3.0.0)
+    simplecov (0.21.2)
+      docile (~> 1.1)
+      simplecov-html (~> 0.11)
+      simplecov_json_formatter (~> 0.1)
+    simplecov-cobertura (2.1.0)
+      rexml
+      simplecov (~> 0.19)
+    simplecov-html (0.12.3)
+    simplecov_json_formatter (0.1.4)
     solve (4.0.3)
       molinillo (~> 0.6)
       semverse (>= 1.1, < 4.0)
@@ -456,6 +466,7 @@
   rspec
   rspec-parameterized
   rspec_junit_formatter
+  simplecov-cobertura
   thor (= 0.18.1)
   yard
 
diff --git a/gitlab-ci-config/gitlab-com.yml b/gitlab-ci-config/gitlab-com.yml
index 7d98dc6951e0c39af4ebec63b9ebec4e9871961c_Z2l0bGFiLWNpLWNvbmZpZy9naXRsYWItY29tLnltbA==..59fd71ccf469cb6db4d5d6dcfcb33553f1b77220_Z2l0bGFiLWNpLWNvbmZpZy9naXRsYWItY29tLnltbA== 100644
--- a/gitlab-ci-config/gitlab-com.yml
+++ b/gitlab-ci-config/gitlab-com.yml
@@ -141,7 +141,7 @@
   script:
     - bundle exec rspec --color --format RspecJunitFormatter --out junit_rspec.xml --format documentation spec/lib
   artifacts:
-    reports:
+    reports: &spec_reports
       junit: junit_rspec.xml
 
 .chef_spec_template:
@@ -433,6 +433,11 @@
   extends: .spec_template
   needs:
     - rubocop
+  coverage: '/\(\d+.\d+\%\) covered/'
+  artifacts:
+    reports:
+      <<: *spec_reports
+      cobertura: coverage/coverage.xml
 
 Ubuntu 16.04 specs:
   image: "registry.gitlab.com/gitlab-org/gitlab-build-images:omnibus-gitlab-xenial"
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 7d98dc6951e0c39af4ebec63b9ebec4e9871961c_c3BlYy9zcGVjX2hlbHBlci5yYg==..59fd71ccf469cb6db4d5d6dcfcb33553f1b77220_c3BlYy9zcGVjX2hlbHBlci5yYg== 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,18 @@
 # Just the basic rspec configuration common to all spec testing.
 # Use this if you do not need the full weight of `chef_helper`
 
+require 'simplecov-cobertura'
+
+SimpleCov.start do
+  formatter SimpleCov::Formatter::CoberturaFormatter
+  # SimpleCov does not work for Chef recipes as Chef dynamically loads and
+  # evaluates entire recipes as part of run. This makes SimpleCov think that
+  # everything has been evaluated. Hence, we exclude them.
+  add_filter %r{files/}
+
+  add_group 'Build libraries', 'lib'
+end
+
 require 'rubocop'
 require 'fantaskspec'
 require 'knapsack'