diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py
index 89ed4718687706e0bbcec98f3b5f6c5017009678..36236b0cc161c4cbe2759c7230d9ac5fcb1d31d9 100644
--- a/lib/spack/spack/test/cmd/ci.py
+++ b/lib/spack/spack/test/cmd/ci.py
@@ -18,7 +18,7 @@
 import spack.paths as spack_paths
 import spack.repo as repo
 from spack.spec import Spec
-from spack.test.conftest import MockPackage, MockPackageMultiRepo
+from spack.util.mock_package import MockPackageMultiRepo
 import spack.util.executable as exe
 import spack.util.spack_yaml as syaml
 import spack.util.gpg
@@ -101,15 +101,14 @@ def test_specs_staging(config):
 """
     default = ('build', 'link')
 
-    g = MockPackage('g', [], [])
-    f = MockPackage('f', [], [])
-    e = MockPackage('e', [], [])
-    d = MockPackage('d', [f, g], [default, default])
-    c = MockPackage('c', [], [])
-    b = MockPackage('b', [d, e], [default, default])
-    a = MockPackage('a', [b, c], [default, default])
-
-    mock_repo = MockPackageMultiRepo([a, b, c, d, e, f, g])
+    mock_repo = MockPackageMultiRepo()
+    g = mock_repo.add_package('g', [], [])
+    f = mock_repo.add_package('f', [], [])
+    e = mock_repo.add_package('e', [], [])
+    d = mock_repo.add_package('d', [f, g], [default, default])
+    c = mock_repo.add_package('c', [], [])
+    b = mock_repo.add_package('b', [d, e], [default, default])
+    mock_repo.add_package('a', [b, c], [default, default])
 
     with repo.swap(mock_repo):
         spec_a = Spec('a')
diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py
index 4f3abb4438debcf6548210862ba8d0b5f82e6926..f35b0a4bc138199d2c35a7b9968aebe05cdd45ad 100644
--- a/lib/spack/spack/test/cmd/env.py
+++ b/lib/spack/spack/test/cmd/env.py
@@ -20,7 +20,7 @@
 from spack.stage import stage_prefix
 
 from spack.spec_list import SpecListError
-from spack.test.conftest import MockPackage, MockPackageMultiRepo
+from spack.util.mock_package import MockPackageMultiRepo
 import spack.util.spack_json as sjson
 
 
@@ -733,10 +733,10 @@ def create_v1_lockfile_dict(roots, all_specs):
 def test_read_old_lock_and_write_new(tmpdir):
     build_only = ('build',)
 
-    y = MockPackage('y', [], [])
-    x = MockPackage('x', [y], [build_only])
+    mock_repo = MockPackageMultiRepo()
+    y = mock_repo.add_package('y', [], [])
+    mock_repo.add_package('x', [y], [build_only])
 
-    mock_repo = MockPackageMultiRepo([x, y])
     with spack.repo.swap(mock_repo):
         x = Spec('x')
         x.concretize()
@@ -765,9 +765,9 @@ def test_read_old_lock_creates_backup(tmpdir):
     """When reading a version-1 lockfile, make sure that a backup of that file
     is created.
     """
-    y = MockPackage('y', [], [])
+    mock_repo = MockPackageMultiRepo()
+    y = mock_repo.add_package('y', [], [])
 
-    mock_repo = MockPackageMultiRepo([y])
     with spack.repo.swap(mock_repo):
         y = Spec('y')
         y.concretize()
@@ -796,11 +796,10 @@ def test_indirect_build_dep():
     default = ('build', 'link')
     build_only = ('build',)
 
-    z = MockPackage('z', [], [])
-    y = MockPackage('y', [z], [build_only])
-    x = MockPackage('x', [y], [default])
-
-    mock_repo = MockPackageMultiRepo([x, y, z])
+    mock_repo = MockPackageMultiRepo()
+    z = mock_repo.add_package('z', [], [])
+    y = mock_repo.add_package('y', [z], [build_only])
+    mock_repo.add_package('x', [y], [default])
 
     def noop(*args):
         pass
@@ -838,11 +837,10 @@ def test_store_different_build_deps():
     default = ('build', 'link')
     build_only = ('build',)
 
-    z = MockPackage('z', [], [])
-    y = MockPackage('y', [z], [build_only])
-    x = MockPackage('x', [y, z], [default, build_only])
-
-    mock_repo = MockPackageMultiRepo([x, y, z])
+    mock_repo = MockPackageMultiRepo()
+    z = mock_repo.add_package('z', [], [])
+    y = mock_repo.add_package('y', [z], [build_only])
+    mock_repo.add_package('x', [y, z], [default, build_only])
 
     def noop(*args):
         pass
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 9024c99cadfd211c8ed29e61c2ffb72335feeb6e..232dfaeb4bee17f109802f18e3f89dd210f8993e 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -15,7 +15,7 @@
 from spack.package_prefs import PackagePrefs
 from spack.spec import Spec, CompilerSpec, ConflictsInSpecError
 from spack.version import ver
-from spack.test.conftest import MockPackage, MockPackageMultiRepo
+from spack.util.mock_package import MockPackageMultiRepo
 import spack.compilers
 import spack.platforms.test
 
@@ -235,10 +235,10 @@ def test_architecture_deep_inheritance(self):
         """
         default_dep = ('link', 'build')
 
-        bazpkg = MockPackage('bazpkg', [], [])
-        barpkg = MockPackage('barpkg', [bazpkg], [default_dep])
-        foopkg = MockPackage('foopkg', [barpkg], [default_dep])
-        mock_repo = MockPackageMultiRepo([foopkg, barpkg, bazpkg])
+        mock_repo = MockPackageMultiRepo()
+        bazpkg = mock_repo.add_package('bazpkg', [], [])
+        barpkg = mock_repo.add_package('barpkg', [bazpkg], [default_dep])
+        mock_repo.add_package('foopkg', [barpkg], [default_dep])
 
         with spack.repo.swap(mock_repo):
             spec = Spec('foopkg %clang@3.3 os=CNL target=footar' +
diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py
index 8912c0219b73bf5f3ea5f6e0f006e60f279a593e..736c5a55638ec9af9c4b0fcf7767842a569c720b 100644
--- a/lib/spack/spack/test/conftest.py
+++ b/lib/spack/spack/test/conftest.py
@@ -14,7 +14,6 @@
 import tempfile
 import xml.etree.ElementTree
 
-import ordereddict_backport
 import py
 import pytest
 import ruamel.yaml as yaml
@@ -38,11 +37,8 @@
 import spack.util.gpg
 
 from spack.util.pattern import Bunch
-from spack.dependency import Dependency
 from spack.fetch_strategy import FetchStrategyComposite, URLFetchStrategy
 from spack.fetch_strategy import FetchError
-from spack.spec import Spec
-from spack.version import Version
 
 
 @pytest.fixture
@@ -1004,75 +1000,6 @@ def installation_dir_with_headers(tmpdir_factory):
     return root
 
 
-##########
-# Mock packages
-##########
-
-
-class MockPackage(object):
-    def __init__(self, name, dependencies, dependency_types, conditions=None,
-                 versions=None):
-        self.name = name
-        self.spec = None
-        self.dependencies = ordereddict_backport.OrderedDict()
-        self._installed_upstream = False
-
-        assert len(dependencies) == len(dependency_types)
-        for dep, dtype in zip(dependencies, dependency_types):
-            d = Dependency(self, Spec(dep.name), type=dtype)
-            if not conditions or dep.name not in conditions:
-                self.dependencies[dep.name] = {Spec(name): d}
-            else:
-                dep_conditions = conditions[dep.name]
-                dep_conditions = dict(
-                    (Spec(x), Dependency(self, Spec(y), type=dtype))
-                    for x, y in dep_conditions.items())
-                self.dependencies[dep.name] = dep_conditions
-
-        if versions:
-            self.versions = versions
-        else:
-            versions = list(Version(x) for x in [1, 2, 3])
-            self.versions = dict((x, {'preferred': False}) for x in versions)
-
-        self.variants = {}
-        self.provided = {}
-        self.conflicts = {}
-        self.patches = {}
-
-    def provides(self, vname):
-        return vname in self.provided
-
-    @property
-    def virtuals_provided(self):
-        return [v.name for v, c in self.provided]
-
-
-class MockPackageMultiRepo(object):
-    def __init__(self, packages):
-        self.spec_to_pkg = dict((x.name, x) for x in packages)
-        self.spec_to_pkg.update(
-            dict(('mockrepo.' + x.name, x) for x in packages))
-
-    def get(self, spec):
-        if not isinstance(spec, spack.spec.Spec):
-            spec = Spec(spec)
-        return self.spec_to_pkg[spec.name]
-
-    def get_pkg_class(self, name):
-        return self.spec_to_pkg[name]
-
-    def exists(self, name):
-        return name in self.spec_to_pkg
-
-    def is_virtual(self, name):
-        return False
-
-    def repo_for_pkg(self, name):
-        import collections
-        Repo = collections.namedtuple('Repo', ['namespace'])
-        return Repo('mockrepo')
-
 ##########
 # Specs of various kind
 ##########
diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py
index 28311c7501ddb97fcf1851c04246bcbba0fbcb93..70f9bffe59b0b0f4d182257fd72b9e28d1294425 100644
--- a/lib/spack/spack/test/database.py
+++ b/lib/spack/spack/test/database.py
@@ -28,7 +28,7 @@
 import spack.database
 import spack.package
 import spack.spec
-from spack.test.conftest import MockPackage, MockPackageMultiRepo
+from spack.util.mock_package import MockPackageMultiRepo
 from spack.util.executable import Executable
 
 
@@ -73,11 +73,11 @@ def test_installed_upstream(upstream_and_downstream_db):
         downstream_db, downstream_layout = (upstream_and_downstream_db)
 
     default = ('build', 'link')
-    x = MockPackage('x', [], [])
-    z = MockPackage('z', [], [])
-    y = MockPackage('y', [z], [default])
-    w = MockPackage('w', [x, y], [default, default])
-    mock_repo = MockPackageMultiRepo([w, x, y, z])
+    mock_repo = MockPackageMultiRepo()
+    x = mock_repo.add_package('x', [], [])
+    z = mock_repo.add_package('z', [], [])
+    y = mock_repo.add_package('y', [z], [default])
+    mock_repo.add_package('w', [x, y], [default, default])
 
     with spack.repo.swap(mock_repo):
         spec = spack.spec.Spec('w')
@@ -116,9 +116,9 @@ def test_removed_upstream_dep(upstream_and_downstream_db):
         downstream_db, downstream_layout = (upstream_and_downstream_db)
 
     default = ('build', 'link')
-    z = MockPackage('z', [], [])
-    y = MockPackage('y', [z], [default])
-    mock_repo = MockPackageMultiRepo([y, z])
+    mock_repo = MockPackageMultiRepo()
+    z = mock_repo.add_package('z', [], [])
+    mock_repo.add_package('y', [z], [default])
 
     with spack.repo.swap(mock_repo):
         spec = spack.spec.Spec('y')
@@ -150,8 +150,8 @@ def test_add_to_upstream_after_downstream(upstream_and_downstream_db):
     upstream_write_db, upstream_db, upstream_layout,\
         downstream_db, downstream_layout = (upstream_and_downstream_db)
 
-    x = MockPackage('x', [], [])
-    mock_repo = MockPackageMultiRepo([x])
+    mock_repo = MockPackageMultiRepo()
+    mock_repo.add_package('x', [], [])
 
     with spack.repo.swap(mock_repo):
         spec = spack.spec.Spec('x')
@@ -183,8 +183,8 @@ def test_cannot_write_upstream(tmpdir_factory, test_store, gen_mock_layout):
     roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b']]
     layouts = [gen_mock_layout(x) for x in ['/ra/', '/rb/']]
 
-    x = MockPackage('x', [], [])
-    mock_repo = MockPackageMultiRepo([x])
+    mock_repo = MockPackageMultiRepo()
+    mock_repo.add_package('x', [], [])
 
     # Instantiate the database that will be used as the upstream DB and make
     # sure it has an index file
@@ -209,11 +209,10 @@ def test_recursive_upstream_dbs(tmpdir_factory, test_store, gen_mock_layout):
     layouts = [gen_mock_layout(x) for x in ['/ra/', '/rb/', '/rc/']]
 
     default = ('build', 'link')
-    z = MockPackage('z', [], [])
-    y = MockPackage('y', [z], [default])
-    x = MockPackage('x', [y], [default])
-
-    mock_repo = MockPackageMultiRepo([x, y, z])
+    mock_repo = MockPackageMultiRepo()
+    z = mock_repo.add_package('z', [], [])
+    y = mock_repo.add_package('y', [z], [default])
+    mock_repo.add_package('x', [y], [default])
 
     with spack.repo.swap(mock_repo):
         spec = spack.spec.Spec('x')
@@ -675,7 +674,7 @@ def test_115_reindex_with_packages_not_in_repo(mutable_database):
     # Dont add any package definitions to this repository, the idea is that
     # packages should not have to be defined in the repository once they
     # are installed
-    with spack.repo.swap(MockPackageMultiRepo([])):
+    with spack.repo.swap(MockPackageMultiRepo()):
         spack.store.store.reindex()
         _check_db_sanity(mutable_database)
 
diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py
index e031f02c255800d5e1458732c46d795ac6f65ee7..0b638ada04fb5598774cc47e92033f00ac912dc6 100644
--- a/lib/spack/spack/test/spec_dag.py
+++ b/lib/spack/spack/test/spec_dag.py
@@ -12,7 +12,7 @@
 
 from spack.spec import Spec
 from spack.dependency import all_deptypes, Dependency, canonical_deptype
-from spack.test.conftest import MockPackage, MockPackageMultiRepo
+from spack.util.mock_package import MockPackageMultiRepo
 
 
 def check_links(spec_to_check):
@@ -69,12 +69,12 @@ def test_test_deptype():
     default = ('build', 'link')
     test_only = ('test',)
 
-    x = MockPackage('x', [], [])
-    z = MockPackage('z', [], [])
-    y = MockPackage('y', [z], [test_only])
-    w = MockPackage('w', [x, y], [test_only, default])
+    mock_repo = MockPackageMultiRepo()
+    x = mock_repo.add_package('x', [], [])
+    z = mock_repo.add_package('z', [], [])
+    y = mock_repo.add_package('y', [z], [test_only])
+    w = mock_repo.add_package('w', [x, y], [test_only, default])
 
-    mock_repo = MockPackageMultiRepo([w, x, y, z])
     with spack.repo.swap(mock_repo):
         spec = Spec('w')
         spec.concretize(tests=(w.name,))
@@ -93,8 +93,9 @@ def test_installed_deps():
     default = ('build', 'link')
     build_only = ('build',)
 
-    e = MockPackage('e', [], [])
-    d = MockPackage('d', [], [])
+    mock_repo = MockPackageMultiRepo()
+    e = mock_repo.add_package('e', [], [])
+    d = mock_repo.add_package('d', [], [])
     c_conditions = {
         d.name: {
             'c': 'd@2'
@@ -103,11 +104,10 @@ def test_installed_deps():
             'c': 'e@2'
         }
     }
-    c = MockPackage('c', [d, e], [build_only, default],
-                    conditions=c_conditions)
-    b = MockPackage('b', [d, e], [default, default])
-    a = MockPackage('a', [b, c], [default, default])
-    mock_repo = MockPackageMultiRepo([a, b, c, d, e])
+    c = mock_repo.add_package('c', [d, e], [build_only, default],
+                              conditions=c_conditions)
+    b = mock_repo.add_package('b', [d, e], [default, default])
+    mock_repo.add_package('a', [b, c], [default, default])
 
     with spack.repo.swap(mock_repo):
         c_spec = Spec('c')
@@ -133,10 +133,10 @@ def test_specify_preinstalled_dep():
     """
     default = ('build', 'link')
 
-    c = MockPackage('c', [], [])
-    b = MockPackage('b', [c], [default])
-    a = MockPackage('a', [b], [default])
-    mock_repo = MockPackageMultiRepo([a, b, c])
+    mock_repo = MockPackageMultiRepo()
+    c = mock_repo.add_package('c', [], [])
+    b = mock_repo.add_package('b', [c], [default])
+    mock_repo.add_package('a', [b], [default])
 
     with spack.repo.swap(mock_repo):
         b_spec = Spec('b')
@@ -161,15 +161,15 @@ def test_conditional_dep_with_user_constraints():
     """
     default = ('build', 'link')
 
-    y = MockPackage('y', [], [])
+    mock_repo = MockPackageMultiRepo()
+    y = mock_repo.add_package('y', [], [])
     x_on_y_conditions = {
         y.name: {
             'x@2:': 'y'
         }
     }
-    x = MockPackage('x', [y], [default], conditions=x_on_y_conditions)
+    mock_repo.add_package('x', [y], [default], conditions=x_on_y_conditions)
 
-    mock_repo = MockPackageMultiRepo([x, y])
     with spack.repo.swap(mock_repo):
         spec = Spec('x ^y@2')
         spec.concretize()
diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py
index f9b41df19a106d39d342fb909b794f48da2481fe..03129a7eb9bb748c54a4499f7772fbae76bf7bfb 100644
--- a/lib/spack/spack/test/spec_yaml.py
+++ b/lib/spack/spack/test/spec_yaml.py
@@ -26,7 +26,7 @@
 from spack import repo
 from spack.spec import Spec, save_dependency_spec_yamls
 from spack.util.spack_yaml import syaml_dict
-from spack.test.conftest import MockPackage, MockPackageMultiRepo
+from spack.util.mock_package import MockPackageMultiRepo
 
 
 def check_yaml_round_trip(spec):
@@ -301,15 +301,14 @@ def test_save_dependency_spec_yamls_subset(tmpdir, config):
 
     default = ('build', 'link')
 
-    g = MockPackage('g', [], [])
-    f = MockPackage('f', [], [])
-    e = MockPackage('e', [], [])
-    d = MockPackage('d', [f, g], [default, default])
-    c = MockPackage('c', [], [])
-    b = MockPackage('b', [d, e], [default, default])
-    a = MockPackage('a', [b, c], [default, default])
-
-    mock_repo = MockPackageMultiRepo([a, b, c, d, e, f, g])
+    mock_repo = MockPackageMultiRepo()
+    g = mock_repo.add_package('g', [], [])
+    f = mock_repo.add_package('f', [], [])
+    e = mock_repo.add_package('e', [], [])
+    d = mock_repo.add_package('d', [f, g], [default, default])
+    c = mock_repo.add_package('c', [], [])
+    b = mock_repo.add_package('b', [d, e], [default, default])
+    mock_repo.add_package('a', [b, c], [default, default])
 
     with repo.swap(mock_repo):
         spec_a = Spec('a')
diff --git a/lib/spack/spack/test/util/mock_package.py b/lib/spack/spack/test/util/mock_package.py
new file mode 100644
index 0000000000000000000000000000000000000000..376ac581bd5871d4a00d42027563d0bde00d8ca9
--- /dev/null
+++ b/lib/spack/spack/test/util/mock_package.py
@@ -0,0 +1,43 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import spack.repo
+from spack.util.mock_package import MockPackageMultiRepo
+
+
+def test_mock_package_possible_dependencies():
+    mock_repo = MockPackageMultiRepo()
+    e = mock_repo.add_package('e')
+    d = mock_repo.add_package('d', [e])
+    c = mock_repo.add_package('c', [d])
+    b = mock_repo.add_package('b', [d])
+    a = mock_repo.add_package('a', [b, c])
+
+    with spack.repo.swap(mock_repo):
+        assert set(a.possible_dependencies()) == set(['a', 'b', 'c', 'd', 'e'])
+        assert set(b.possible_dependencies()) == set(['b', 'd', 'e'])
+        assert set(c.possible_dependencies()) == set(['c', 'd', 'e'])
+        assert set(d.possible_dependencies()) == set(['d', 'e'])
+        assert set(e.possible_dependencies()) == set(['e'])
+
+        assert set(
+            a.possible_dependencies(transitive=False)) == set(['a', 'b', 'c'])
+        assert set(
+            b.possible_dependencies(transitive=False)) == set(['b', 'd'])
+        assert set(
+            c.possible_dependencies(transitive=False)) == set(['c', 'd'])
+        assert set(
+            d.possible_dependencies(transitive=False)) == set(['d', 'e'])
+        assert set(
+            e.possible_dependencies(transitive=False)) == set(['e'])
+
+
+def test_mock_repo_is_virtual():
+    mock_repo = MockPackageMultiRepo()
+
+    # current implementation is always false
+    assert mock_repo.is_virtual("foo") is False
+    assert mock_repo.is_virtual("bar") is False
+    assert mock_repo.is_virtual("baz") is False
diff --git a/lib/spack/spack/util/mock_package.py b/lib/spack/spack/util/mock_package.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d8ae30b103b1e2f626681f6ba51caf9808b73e4
--- /dev/null
+++ b/lib/spack/spack/util/mock_package.py
@@ -0,0 +1,161 @@
+# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+"""Infrastructure used by tests for mocking packages and repos."""
+
+import ordereddict_backport
+
+import spack.util.naming
+from spack.dependency import Dependency
+from spack.spec import Spec
+from spack.version import Version
+
+__all__ = ["MockPackageMultiRepo"]
+
+
+class MockPackageBase(object):
+    """Internal base class for mocking ``spack.package.PackageBase``.
+
+    Use ``MockPackageMultiRepo.add_package()`` to create new instances.
+
+    """
+    def __init__(self, dependencies, dependency_types,
+                 conditions=None, versions=None):
+        """Instantiate a new MockPackageBase.
+
+        This is not for general use; it needs to be constructed by a
+        ``MockPackageMultiRepo``, as we need to know about *all* packages
+        to find possible depenencies.
+
+        """
+        self.spec = None
+        self._installed_upstream = False
+
+    def provides(self, vname):
+        return vname in self.provided
+
+    @property
+    def virtuals_provided(self):
+        return [v.name for v, c in self.provided]
+
+    @classmethod
+    def possible_dependencies(
+            cls, transitive=True, deptype='all', visited=None, virtuals=None):
+        visited = {} if visited is None else visited
+
+        for name, conditions in cls.dependencies.items():
+            # check whether this dependency could be of the type asked for
+            types = [dep.type for cond, dep in conditions.items()]
+            types = set.union(*types)
+            if not any(d in types for d in deptype):
+                continue
+
+        visited.setdefault(cls.name, set())
+        for dep_name in cls.dependencies:
+            if dep_name in visited:
+                continue
+
+            visited.setdefault(dep_name, set())
+
+            if not transitive:
+                continue
+
+            cls._repo.get(dep_name).possible_dependencies(
+                transitive, deptype, visited, virtuals)
+
+        return visited
+
+
+class MockPackageMultiRepo(object):
+    """Mock package repository, mimicking ``spack.repo.Repo``."""
+
+    def __init__(self):
+        self.spec_to_pkg = {}
+
+    def get(self, spec):
+        if not isinstance(spec, spack.spec.Spec):
+            spec = Spec(spec)
+        return self.spec_to_pkg[spec.name]
+
+    def get_pkg_class(self, name):
+        return self.spec_to_pkg[name]
+
+    def exists(self, name):
+        return name in self.spec_to_pkg
+
+    def is_virtual(self, name):
+        return False
+
+    def repo_for_pkg(self, name):
+        import collections
+        Repo = collections.namedtuple('Repo', ['namespace'])
+        return Repo('mockrepo')
+
+    def add_package(self, name, dependencies=None, dependency_types=None,
+                    conditions=None):
+        """Factory method for creating mock packages.
+
+        This creates a new subclass of ``MockPackageBase``, ensures that its
+        ``name`` and ``__name__`` properties are set up correctly, and
+        returns a new instance.
+
+        We use a factory function here because many functions and properties
+        of packages need to be class functions.
+
+        Args:
+            name (str): name of the new package
+            dependencies (list): list of mock packages to be dependencies
+                for this new package (optional; no deps if not provided)
+            dependency_type (list): list of deptypes for each dependency
+                (optional; will be default_deptype if not provided)
+            conditions (list): condition specs for each dependency (optional)
+
+        """
+        if not dependencies:
+            dependencies = []
+
+        if not dependency_types:
+            dependency_types = [
+                spack.dependency.default_deptype] * len(dependencies)
+
+        assert len(dependencies) == len(dependency_types)
+
+        # new class for the mock package
+        class MockPackage(MockPackageBase):
+            pass
+        MockPackage.__name__ = spack.util.naming.mod_to_class(name)
+        MockPackage.name = name
+        MockPackage._repo = self
+
+        # set up dependencies
+        MockPackage.dependencies = ordereddict_backport.OrderedDict()
+        for dep, dtype in zip(dependencies, dependency_types):
+            d = Dependency(MockPackage, Spec(dep.name), type=dtype)
+            if not conditions or dep.name not in conditions:
+                MockPackage.dependencies[dep.name] = {Spec(name): d}
+            else:
+                dep_conditions = conditions[dep.name]
+                dep_conditions = dict(
+                    (Spec(x), Dependency(MockPackage, Spec(y), type=dtype))
+                    for x, y in dep_conditions.items())
+                MockPackage.dependencies[dep.name] = dep_conditions
+
+        # each package has some fake versions
+        versions = list(Version(x) for x in [1, 2, 3])
+        MockPackage.versions = dict(
+            (x, {'preferred': False}) for x in versions
+        )
+
+        MockPackage.variants = {}
+        MockPackage.provided = {}
+        MockPackage.conflicts = {}
+        MockPackage.patches = {}
+
+        mock_package = MockPackage(
+            dependencies, dependency_types, conditions, versions)
+        self.spec_to_pkg[name] = mock_package
+        self.spec_to_pkg["mockrepo." + name] = mock_package
+
+        return mock_package