diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/test_build.py b/tests/test_build.py
index 538ff73faa76c5ac9fa6e38ee67d24c153829e81..c07c9bd4915c8d7e64ea2fe5b29d3b3687e80df8 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -4,61 +4,30 @@ import subprocess
 from distutils import dir_util
 from git import Repo
 from pathlib import Path
+from .utils import *
 
 
 TEST_DATA = Path(__file__).absolute().parent / "data"
 
-MAKEFILE_TEMPLATE = """
-where_am_I := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
-include $(E3_REQUIRE_TOOLS)/driver.makefile
 
-TEMPLATES += {templates}
-SOURCES += {sources}
-DBDS += {dbds}
-HEADERS += {headers}
+@pytest.mark.parametrize(
+    "wrapper",
+    [{"templates": "database.db", "sources": "", "dbds": "", "headers": ""}],
+    indirect=True,
+)
+def test_patch(wrapper):
+    wrapper_dir = wrapper
 
-db:
-
-.PHONY: db
-"""
-
-
-def write_makefile_template(dst, templates=[], sources=[], dbds=[], headers=[]):
-    makefile_txt = MAKEFILE_TEMPLATE.format(
-        templates=" ".join(templates),
-        sources=" ".join(sources),
-        dbds=" ".join(dbds),
-        headers=" ".join(headers),
-    )
-    with open(dst / "build.Makefile", "w") as f:
-        f.write(makefile_txt)
-
-
-def run_make(wrapper_dir, *cmds):
-    make_cmd = ["make", "-C", wrapper_dir]
-    p = subprocess.Popen(
-        make_cmd + list(cmds), stdout=subprocess.PIPE, stderr=subprocess.PIPE
+    rc, outs, _ = run_make(
+        wrapper_dir,
+        "init",
+        __DEBUG_VERSION="0.0.0",
     )
-    return p.communicate()
-
-
-@pytest.fixture
-def e3_wrapper(tmpdir):
-    dst_dir = tmpdir / "wrapper"
-    dir_util.copy_tree(str(TEST_DATA), str(dst_dir))
-    r = Repo.init(dst_dir)
-    yield r
-
-
-def test_patch(e3_wrapper):
-    print(e3_wrapper)
-    wrapper_dir = Path(e3_wrapper.working_dir)
-    write_makefile_template(wrapper_dir, templates=["database.db"])
-
-    outs, _ = run_make(wrapper_dir, "init")
+    assert rc == 0
     assert "You are in the local source mode" in outs.decode("utf-8")
 
-    run_make(wrapper_dir, "patch")
+    rc, _, _ = run_make(wrapper_dir, "patch")
+    assert rc == 0
     with open(wrapper_dir / "build" / "database.db", "r") as f:
         db_contents = f.read()
     assert 'field(DESC, "OK")' in db_contents
diff --git a/tests/test_versions.py b/tests/test_versions.py
index 2b1f8f7b35e6ad16935151586433f759eb2c22e6..6d18e3d6046b92a2ea97f0bea520007c2a9da6f5 100644
--- a/tests/test_versions.py
+++ b/tests/test_versions.py
@@ -1,86 +1,24 @@
 import os
 import re
-import subprocess
-import time
 from pathlib import Path
 
 import pytest
-from run_iocsh import IOC
+
+from .utils import *
 
 TEST_DATA = Path(__file__).absolute().parent / "data"
-EPICS_BASE = os.environ.get("EPICS_BASE")
-E3_REQUIRE_VERSION = os.environ.get("E3_REQUIRE_VERSION")
-IOCSH_PATH = Path(EPICS_BASE) / "require" / E3_REQUIRE_VERSION / "bin" / "iocsh.bash"
 
 TEST_MODULE_NAME = "testversions"
 
 RE_MODULE_LOADED = f"Loaded {TEST_MODULE_NAME} version {{version}}"
 RE_MODULE_NOT_LOADED = f"Module {TEST_MODULE_NAME} (not available|version {{required}} not available|version {{required}} not available \\(but other versions are available\\))"
 
-CONFIG = f"""
-TOP:=$(CURDIR)
-
-# To configure require
-EPICS_BASE:=$(__EPICS_BASE_LOCATION)
-E3_REQUIRE_VERSION:=$(__REQUIRE_VERSION)
-
-E3_REQUIRE_LOCATION := $(EPICS_BASE)/require/$(E3_REQUIRE_VERSION)
-REQUIRE_CONFIG := $(E3_REQUIRE_LOCATION)/configure
-
-# To configure the modules
-EPICS_MODULE_NAME:={TEST_MODULE_NAME}
-E3_MODULE_VERSION:=$(__DEBUG_VERSION)
-E3_MODULE_NAME:=$(EPICS_MODULE_NAME)
-E3_MODULE_SRC_PATH:=$(EPICS_MODULE_NAME)
-E3_MODULE_MAKEFILE:=$(EPICS_MODULE_NAME).Makefile
-
-include $(REQUIRE_CONFIG)/CONFIG
-include $(REQUIRE_CONFIG)/RULES_SITEMODS
-
-.PHONY: db
-db:
-"""
-
-MODULE_MAKEFILE = """
-where_am_I := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
-include $(E3_REQUIRE_TOOLS)/driver.makefile
-
-DBDS      += ./test.dbd
-"""
-
-
-def run_make(path, *args, **kwargs):
-    test_env = os.environ.copy()
-    for kw in kwargs:
-        test_env[kw] = kwargs[kw]
-    make_cmd = ["make", "-C", path] + list(args)
-    p = subprocess.Popen(
-        make_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=test_env
-    )
-    outs, errs = p.communicate()
-    return p.returncode, outs, errs
-
-
-def run_ioc_get_output(version, cell_path):
-    with IOC("-r", f"{TEST_MODULE_NAME},{version}", "-l", cell_path) as ioc:
-        time.sleep(1)
-    return ioc.proc.returncode, ioc.outs, ioc.errs
-
-
-@pytest.fixture
-def wrapper(tmpdir):
-    wrapper_dir = Path(tmpdir / "wrapper")
-    test_dir = wrapper_dir / TEST_MODULE_NAME
-    test_dir.mkdir(parents=True)
-    with open(wrapper_dir / "Makefile", "w") as f:
-        f.write(CONFIG)
-    with open(wrapper_dir / f"{TEST_MODULE_NAME}.Makefile", "w") as f:
-        f.write(MODULE_MAKEFILE)
-    with open(wrapper_dir / TEST_MODULE_NAME / "test.dbd", "w") as f:
-        f.write("")
-    yield wrapper_dir
-
 
+@pytest.mark.parametrize(
+    "wrapper",
+    [{"templates": "", "sources": "", "dbds": "test.dbd", "headers": ""}],
+    indirect=True,
+)
 @pytest.mark.parametrize(
     "requested, expected, installed",
     [
@@ -109,14 +47,14 @@ def wrapper(tmpdir):
 )
 def test_version(wrapper, requested, expected, installed):
     for version in installed:
-        returncode, _, _ = run_make(
+        returncode, o, e = run_make(
             wrapper,
             "clean",
             "cellinstall",
-            __EPICS_BASE_LOCATION=EPICS_BASE,
-            __REQUIRE_VERSION=E3_REQUIRE_VERSION,
             __DEBUG_VERSION=version,
         )
+        print(o)
+        print(e)
         assert returncode == 0
 
     rc, o, e = run_ioc_get_output(requested, wrapper / "cellMods")
diff --git a/tests/utils.py b/tests/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2b416c45503b24f3601d021becb9d12ea6ba5eb
--- /dev/null
+++ b/tests/utils.py
@@ -0,0 +1,82 @@
+import os
+import pytest
+import subprocess
+import time
+from pathlib import Path
+from run_iocsh import IOC
+from git import Repo
+
+
+TEST_MODULE_NAME = "testversions"
+EPICS_BASE = os.environ.get("EPICS_BASE")
+E3_REQUIRE_VERSION = os.environ.get("E3_REQUIRE_VERSION")
+
+CONFIG = f"""
+TOP:=$(CURDIR)
+
+# To configure require
+EPICS_BASE:=$(__EPICS_BASE_LOCATION)
+E3_REQUIRE_VERSION:=$(__REQUIRE_VERSION)
+
+E3_REQUIRE_LOCATION := $(EPICS_BASE)/require/$(E3_REQUIRE_VERSION)
+REQUIRE_CONFIG := $(E3_REQUIRE_LOCATION)/configure
+
+# To configure the modules
+EPICS_MODULE_NAME:={TEST_MODULE_NAME}
+E3_MODULE_VERSION:=$(__DEBUG_VERSION)
+E3_MODULE_NAME:=$(EPICS_MODULE_NAME)
+E3_MODULE_SRC_PATH:=$(EPICS_MODULE_NAME)
+E3_MODULE_MAKEFILE:=$(EPICS_MODULE_NAME).Makefile
+
+include $(REQUIRE_CONFIG)/CONFIG
+include $(REQUIRE_CONFIG)/RULES_SITEMODS
+"""
+
+MODULE_MAKEFILE = """
+where_am_I := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+include $(E3_REQUIRE_TOOLS)/driver.makefile
+
+TEMPLATES += {templates}
+SOURCES += {sources}
+DBDS += {dbds}
+HEADERS += {headers}
+"""
+
+TEST_MODULE_NAME = "testversions"
+
+
+def run_make(path, *args, **kwargs):
+    test_env = os.environ.copy()
+    test_env["__EPICS_BASE_LOCATION"] = EPICS_BASE
+    test_env["__REQUIRE_VERSION"] = E3_REQUIRE_VERSION
+    for kw in kwargs:
+        test_env[kw] = kwargs[kw]
+    make_cmd = ["make", "-C", path] + list(args)
+    p = subprocess.Popen(
+        make_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=test_env
+    )
+    outs, errs = p.communicate()
+    return p.returncode, outs, errs
+
+
+def run_ioc_get_output(version, cell_path):
+    with IOC("-r", f"{TEST_MODULE_NAME},{version}", "-l", cell_path) as ioc:
+        time.sleep(1)
+    return ioc.proc.returncode, ioc.outs, ioc.errs
+
+
+@pytest.fixture
+def wrapper(tmpdir, request):
+    wrapper_dir = Path(tmpdir / "wrapper")
+    test_dir = wrapper_dir / TEST_MODULE_NAME
+    test_dir.mkdir(parents=True)
+
+    # TODO: This should not be necessary, but it is for patching.
+    Repo.init(wrapper_dir)
+    with open(wrapper_dir / "Makefile", "w") as f:
+        f.write(CONFIG)
+    with open(wrapper_dir / f"{TEST_MODULE_NAME}.Makefile", "w") as f:
+        f.write(MODULE_MAKEFILE.format(**request.param))
+    with open(wrapper_dir / TEST_MODULE_NAME / "test.dbd", "w") as f:
+        f.write("")
+    yield wrapper_dir