diff --git a/.coveragerc b/.coveragerc
index ecb5a81..5d31ba1 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,7 +1,6 @@
 [run]
 branch = True
 source = validations-common
-omit = validations-common/openstack/*
 
 [report]
 ignore_errors = True
diff --git a/.gitignore b/.gitignore
index 476c0d9..0a45f05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,7 +29,7 @@ cover/
 nosetests.xml
 .testrepository
 .venv
-.stestr/
+.stestr/*
 
 # Translations
 *.mo
diff --git a/.stestr.conf b/.stestr.conf
index 1178528..fbcfc59 100644
--- a/.stestr.conf
+++ b/.stestr.conf
@@ -1,3 +1,3 @@
 [DEFAULT]
-test_path=./validations_common/tests
+test_path=${TEST_PATH:-./validations_common/tests}
 top_dir=./
diff --git a/.zuul.yaml b/.zuul.yaml
index 7891c3d..dd2c565 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -38,6 +38,7 @@
     check:
       jobs:
         - openstack-tox-linters
+        - openstack-tox-cover
         - validations-common-functional
     gate:
       jobs:
diff --git a/tox.ini b/tox.ini
index 1b85525..1f2a13f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,9 +3,15 @@ minversion = 3.2.0
 envlist = linters,docs,py38,molecule
 skipdist = True
 
+# Automatic envs (pyXX) will only use the python version appropriate to that
+# env and ignore basepython inherited from [testenv] if we set
+# ignore_basepython_conflict.
+ignore_basepython_conflict = True
+
 [testenv]
 usedevelop = True
-passenv = *
+passenv =
+  TERM
 setenv =
   ANSIBLE_CALLBACK_PLUGINS={toxinidir}/validations_common/callback_plugins
   ANSIBLE_LOOKUP_PLUGINS={toxinidir}/validations_common/lookup_plugins
@@ -18,11 +24,13 @@ setenv =
   # pip: Avoid 2020-01-01 warnings: https://github.com/pypa/pip/issues/6207
   # paramiko CryptographyDeprecationWarning: https://github.com/ansible/ansible/issues/52598
   PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command,ignore::UserWarning
-  PIP_DISABLE_PIP_VERSION_CHECK=1
+  PIP_+  VIRTUAL_ENV={envdir}
+  LANG=en_US.UTF-8
+  LANGUAGE=en_US:en
+  LC_ALL=C
+  HOME={envdir}DISABLE_PIP_VERSION_CHECK=1
 commands =
-  stestr run {posargs}
-  stestr slowest
-sitepackages = True
+  stestr run --slowest --color {posargs}
 deps =
     -c {env:TOX_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt}
     -r {toxinidir}/requirements.txt
@@ -97,12 +105,21 @@ deps = -r{toxinidir}/doc/requirements.txt
 commands =
     sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
 
+[testenv:venv]
+commands = {posargs}
+passenv = *
+
 [testenv:cover]
-deps =
-    -r {toxinidir}/requirements.txt
-    -r {toxinidir}/test-requirements.txt
-    -r {toxinidir}/molecule-requirements.txt
-commands = python setup.py test --coverage --testr-args='{posargs}'
+setenv =
+  PYTHON=coverage run --source validations_common --parallel-mode
+  HOME={envdir}
+commands =
+  coverage erase
+  stestr run --color {posargs}
+  coverage combine
+  coverage html -d cover
+  coverage xml -o cover/coverage.xml
+  coverage report
 
 [testenv:docs]
 deps =