diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ba4be96d07c261b55a7fb3983e13fd40b52fdbed..ebc3a326b4c92d1a155010ca445e66c2b3abd303 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -224,6 +224,7 @@ unit test workflow:
     variables:
         SERVICE_NAME: "workflow"
         PATH_PREFIX: "services/"
+        PATH_PREFIX2: "shared/workspaces/test/"
     extends: .unit-test
 
 unit test capability:
@@ -232,6 +233,7 @@ unit test capability:
     variables:
         SERVICE_NAME: "capability"
         PATH_PREFIX: "services/"
+        PATH_PREFIX2: "shared/workspaces/test/"
     extends: .unit-test
 
 unit test notification:
@@ -240,6 +242,7 @@ unit test notification:
     variables:
         SERVICE_NAME: "notification"
         PATH_PREFIX: "services/"
+        PATH_PREFIX2: "shared/workspaces/test/"
     extends: .unit-test
 
 
diff --git a/docker-compose.local.yml b/docker-compose.local.yml
index 52ed048ed899f6c252b416fd41645abe022dce22..fa0a13e6661398955a75e2e4eced919d75ca33f5 100644
--- a/docker-compose.local.yml
+++ b/docker-compose.local.yml
@@ -52,7 +52,7 @@ services:
       context: .
       dockerfile: ./config/htcondor/cm/Dockerfile.local
     ports:
-      - 9618
+      - "9618"
 
   condor-execute:
     build:
@@ -202,7 +202,6 @@ services:
       - ./services/capability:/code/services/capability
       - ./shared:/code/shared
       - ./apps/cli:/code/apps/cli
-#      - ./testing:/code/testing
 
 
   notification:
@@ -231,9 +230,6 @@ services:
       - ./docker.properties:/home/ssa/capo/docker.properties
       - ./services/notification:/code/services/notification
       - ./shared:/code/shared
-#      - ./apps/cli:/code/apps/cli
-#      - ./testing:/code/testing
-
 
   frontend:
     build:
diff --git a/services/capability/poetry.lock b/services/capability/poetry.lock
index 2f47bf8d67ad449bcf3838588abcf6199c8068ae..cd3d0815eb646f881124f34cb4f5735760474c93 100644
--- a/services/capability/poetry.lock
+++ b/services/capability/poetry.lock
@@ -32,6 +32,25 @@ files = [
 [package.dependencies]
 vine = ">=5.0.0"
 
+[[package]]
+name = "attrs"
+version = "23.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
+    {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
+]
+
+[package.extras]
+cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
+dev = ["attrs[tests]", "pre-commit"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
+tests = ["attrs[tests-no-zope]", "zope-interface"]
+tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
+tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
+
 [[package]]
 name = "beaker"
 version = "1.12.1"
@@ -552,6 +571,38 @@ files = [
 docs = ["Sphinx", "pylons-sphinx-themes", "setuptools", "watchdog"]
 testing = ["mock", "pytest", "pytest-cov", "watchdog"]
 
+[[package]]
+name = "hypothesis"
+version = "6.87.1"
+description = "A library for property-based testing"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "hypothesis-6.87.1-py3-none-any.whl", hash = "sha256:6b03e774d7ddddc29810e58ba4c41b5c9a894427aaf336e6400c560655a7449b"},
+    {file = "hypothesis-6.87.1.tar.gz", hash = "sha256:13615a8f7fa27d102c43ab2f92eaef519988700f3ca8129bc6340d36dec372dd"},
+]
+
+[package.dependencies]
+attrs = ">=19.2.0"
+exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
+sortedcontainers = ">=2.1.0,<3.0.0"
+
+[package.extras]
+all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=3.2)", "dpcontracts (>=0.4)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2023.3)"]
+cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"]
+codemods = ["libcst (>=0.3.16)"]
+dateutil = ["python-dateutil (>=1.4)"]
+django = ["django (>=3.2)"]
+dpcontracts = ["dpcontracts (>=0.4)"]
+ghostwriter = ["black (>=19.10b0)"]
+lark = ["lark (>=0.10.1)"]
+numpy = ["numpy (>=1.17.3)"]
+pandas = ["pandas (>=1.1)"]
+pytest = ["pytest (>=4.6)"]
+pytz = ["pytz (>=2014.1)"]
+redis = ["redis (>=3.0.0)"]
+zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.3)"]
+
 [[package]]
 name = "idna"
 version = "3.4"
@@ -743,6 +794,20 @@ sqlalchemy = "1.4.49"
 type = "directory"
 url = "../../shared/messaging"
 
+[[package]]
+name = "mock-alchemy"
+version = "0.2.1"
+description = "SQLAlchemy mock helpers."
+optional = false
+python-versions = ">=3.7,<4.0"
+files = [
+    {file = "mock-alchemy-0.2.1.tar.gz", hash = "sha256:05d15cd8c70266a15dc47e101446996f9b5cc61e01a2c91fc0e8408647983849"},
+    {file = "mock_alchemy-0.2.1-py3-none-any.whl", hash = "sha256:ff606f210600e053a30d0b2ba1e3b55ff3bc9c5b848fce7d8145131c6e964785"},
+]
+
+[package.dependencies]
+SQLAlchemy = ">=1.3.22,<2.0.0"
+
 [[package]]
 name = "mysqlclient"
 version = "2.1.1"
@@ -1287,6 +1352,17 @@ files = [
     {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
 ]
 
+[[package]]
+name = "sortedcontainers"
+version = "2.4.0"
+description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
+optional = false
+python-versions = "*"
+files = [
+    {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
+    {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
+]
+
 [[package]]
 name = "sqlalchemy"
 version = "1.4.49"
@@ -1605,4 +1681,4 @@ test = ["zope.testing"]
 [metadata]
 lock-version = "2.0"
 python-versions = "~3.10"
-content-hash = "eed595656b356b93edda45bf37ede003e100722fd246e548ccfb7c1f0b02cd15"
+content-hash = "fe8417a02c3de534ff5492efe37b174adaa428701ff567a2ea30d3d3a79ab155"
diff --git a/services/capability/pyproject.toml b/services/capability/pyproject.toml
index 6cc282962ff1cb392a24443347d73797413e5f4c..d26762c3541c49d50156487b463cfaea6846c196 100644
--- a/services/capability/pyproject.toml
+++ b/services/capability/pyproject.toml
@@ -39,6 +39,8 @@ pyramid-debugtoolbar = "4.10"
 [tool.poetry.group.test.dependencies]
 pytest = "7.4.2"
 pytest-cov = "4.1.0"
+mock_alchemy = "0.2.1"
+hypothesis = "6.87.1"
 
 [tool.poetry.scripts]
 launch_capability = "capability.capability_launcher:main"
diff --git a/services/workflow/Dockerfile b/services/workflow/Dockerfile
index 32558a54d9e1bfd118a1c6e846eeedae754cc2af..35687677ab2ba00bc84cb41cef720c240771ddc7 100644
--- a/services/workflow/Dockerfile
+++ b/services/workflow/Dockerfile
@@ -37,19 +37,6 @@ RUN addgroup --gid 9233 almapipe && \
 #WORKDIR /home/ssa/capo
 #COPY --chown=vlapipe:vlapipe docker.properties docker.properties
 
-
-USER root
-WORKDIR /code/
-RUN chown vlapipe . && chgrp vlapipe .
-
-# Switch to appuser and install poetry
-USER vlapipe
-RUN curl -sSL https://install.python-poetry.org | python3 -
-
-ENV PATH "${PATH}:/home/vlapipe/.local/bin"
-COPY --chown=vlapipe:vlapipe ./shared ./shared
-COPY --chown=vlapipe:vlapipe ./apps/cli ./apps/cli
-
 # HTCondor install
 USER root
 RUN apt update && apt install -y curl gnupg apt-transport-https
@@ -68,6 +55,14 @@ COPY /config/htcondor/submit/nrao-nofile.conf /etc/security/limits.d/nrao-nofile
 WORKDIR /code
 RUN chown vlapipe . && chgrp vlapipe .
 
+# Switch to appuser and install poetry
+USER vlapipe
+RUN curl -sSL https://install.python-poetry.org | python3 -
+
+ENV PATH "${PATH}:/home/vlapipe/.local/bin"
+COPY --chown=vlapipe:vlapipe ./shared ./shared
+COPY --chown=vlapipe:vlapipe ./apps/cli ./apps/cli
+
 # Copy service directory to /code in the image
 # set ownership of content to vlapipe and the vlapipe group
 USER vlapipe
diff --git a/shared/workspaces/test/capability/__init__.py b/shared/workspaces/test/capability/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/workspaces/test/test_archive_service.py b/shared/workspaces/test/capability/test_archive_service.py
similarity index 100%
rename from shared/workspaces/test/test_archive_service.py
rename to shared/workspaces/test/capability/test_archive_service.py
diff --git a/shared/workspaces/test/test_capability_actions.py b/shared/workspaces/test/capability/test_capability_actions.py
similarity index 99%
rename from shared/workspaces/test/test_capability_actions.py
rename to shared/workspaces/test/capability/test_capability_actions.py
index 9e1971e7c30929526be8c7df46193003235a5311..174609fd92957a6e21e662f7e62436c49b079912 100644
--- a/shared/workspaces/test/test_capability_actions.py
+++ b/shared/workspaces/test/capability/test_capability_actions.py
@@ -47,7 +47,7 @@ from workspaces.capability.services.capability_info import CapabilityInfo
 from workspaces.capability.services.interfaces import ExecutionManagerIF
 from workspaces.notification.services.interfaces import NotificationServiceIF
 
-from .conftest import (
+from test.conftest import (
     SAMPLE_CAPABILITY_NAMES,
     SQLITE_MAX_INT,
     SQLITE_MIN_INT,
diff --git a/shared/workspaces/test/test_capability_architect.py b/shared/workspaces/test/capability/test_capability_architect.py
similarity index 100%
rename from shared/workspaces/test/test_capability_architect.py
rename to shared/workspaces/test/capability/test_capability_architect.py
diff --git a/shared/workspaces/test/test_capability_execution.py b/shared/workspaces/test/capability/test_capability_execution.py
similarity index 100%
rename from shared/workspaces/test/test_capability_execution.py
rename to shared/workspaces/test/capability/test_capability_execution.py
diff --git a/shared/workspaces/test/test_capability_info.py b/shared/workspaces/test/capability/test_capability_info.py
similarity index 99%
rename from shared/workspaces/test/test_capability_info.py
rename to shared/workspaces/test/capability/test_capability_info.py
index a8ab6f42f9d1bff0e86a9b91f906fe5eba6c7a68..769dec58b82599b39d1a4792383518e6b03e795b 100644
--- a/shared/workspaces/test/test_capability_info.py
+++ b/shared/workspaces/test/capability/test_capability_info.py
@@ -43,7 +43,7 @@ from workspaces.capability.schema import (
 )
 from workspaces.capability.services.capability_info import CapabilityInfo
 
-from .conftest import (
+from test.conftest import (
     SAMPLE_CAPABILITY_NAMES,
     SAMPLE_STATE_MACHINES,
     SQLITE_MAX_INT,
@@ -384,7 +384,9 @@ def test_lookup_capability_request(mock_capability_info: CapabilityInfo):
     """
     Can we find a given CapabilityRequest?
     """
-    template = CapabilityTemplate(filename="PPR.xml", content=str.encode("mi CASA es su CASA"))
+    template = CapabilityTemplate(
+        filename="../../../../apps/cli/executables/pexable/vela/test/PPR.xml", content=str.encode("mi CASA es su CASA")
+    )
     capability = Capability()
     capability.name = "std_calibration"
     capability.id = 1
diff --git a/shared/workspaces/test/test_capability_queue.py b/shared/workspaces/test/capability/test_capability_queue.py
similarity index 98%
rename from shared/workspaces/test/test_capability_queue.py
rename to shared/workspaces/test/capability/test_capability_queue.py
index adfd90dbec3d4ef4bb638b661824d7a4668c2d93..19b677d106e39f760bb499d04f58c3615f40994f 100644
--- a/shared/workspaces/test/test_capability_queue.py
+++ b/shared/workspaces/test/capability/test_capability_queue.py
@@ -31,7 +31,7 @@ from workspaces.system.schema import AbstractFile
 from workspaces.workflow.services.workflow_info import WorkflowInfo
 from workspaces.workflow.services.workflow_service import WorkflowService
 
-from .conftest import mock_capability_info, mock_workflow_service
+from test.conftest import mock_capability_info, mock_workflow_service
 
 
 class FakeQueueReporterExecutionManager(ExecutionManagerIF):
diff --git a/shared/workspaces/test/test_capability_request.py b/shared/workspaces/test/capability/test_capability_request.py
similarity index 99%
rename from shared/workspaces/test/test_capability_request.py
rename to shared/workspaces/test/capability/test_capability_request.py
index 3d9ca25d1567d818e7dbac15e32d6eb7d8e99be0..99ae7c2253afb0acdf4c0c4b1d0e8f1dacac42fe 100644
--- a/shared/workspaces/test/test_capability_request.py
+++ b/shared/workspaces/test/capability/test_capability_request.py
@@ -35,7 +35,7 @@ from workspaces.capability.schema import (
 )
 from workspaces.capability.services.capability_info import CapabilityInfo
 
-from .conftest import (
+from test.conftest import (
     SAMPLE_CAPABILITY_NAMES,
     SQLITE_MAX_INT,
     SQLITE_MIN_INT,
diff --git a/shared/workspaces/test/test_capability_service.py b/shared/workspaces/test/capability/test_capability_service.py
similarity index 98%
rename from shared/workspaces/test/test_capability_service.py
rename to shared/workspaces/test/capability/test_capability_service.py
index 45f9bf8d713b344a2c33c41f4a5857273aa9584c..1cfa1dc415498d0b7de87e435973cb16d2ef5ee1 100644
--- a/shared/workspaces/test/test_capability_service.py
+++ b/shared/workspaces/test/capability/test_capability_service.py
@@ -34,7 +34,7 @@ from workspaces.capability.services.capability_info import CapabilityInfo
 from workspaces.capability.services.capability_service import CapabilityService
 from workspaces.notification.services.interfaces import NotificationServiceIF
 
-from .conftest import mock_capability_info, mock_capability_service
+from test.conftest import mock_capability_info, mock_capability_service
 
 
 @pytest.mark.usefixtures("mock_capability_service")
diff --git a/shared/workspaces/test/test_execution_manager.py b/shared/workspaces/test/capability/test_execution_manager.py
similarity index 97%
rename from shared/workspaces/test/test_execution_manager.py
rename to shared/workspaces/test/capability/test_execution_manager.py
index bc496d989374d47096e99b0a1689df36a64510c7..8a1f2a6d255576aac6f9b70c40f30a40164ec09d 100644
--- a/shared/workspaces/test/test_execution_manager.py
+++ b/shared/workspaces/test/capability/test_execution_manager.py
@@ -105,7 +105,9 @@ def fake_execution() -> CapabilityExecution:
 
     :return: fake CapabilityExecution
     """
-    template = CapabilityTemplate(filename="PPR.xml", content=str.encode("foo"))
+    template = CapabilityTemplate(
+        filename="../../../../apps/cli/executables/pexable/vela/test/PPR.xml", content=str.encode("foo")
+    )
     capability = Capability()
     capability.name = "std_calibration"
     capability.id = 1
@@ -234,7 +236,7 @@ def test_submit_workflow_request(
     """
     wf_request = mock_workflow_requests[0]
     wf_req_file = WorkflowRequestFile(
-        filename="PPR.xml",
+        filename="../../../../apps/cli/executables/pexable/vela/test/PPR.xml",
         content=str.encode("I'm a little teapot"),
         workflow_request_id=wf_request.workflow_request_id,
     )
diff --git a/shared/workspaces/test/test_req_state_setter.py b/shared/workspaces/test/capability/test_req_state_setter.py
similarity index 100%
rename from shared/workspaces/test/test_req_state_setter.py
rename to shared/workspaces/test/capability/test_req_state_setter.py
diff --git a/shared/workspaces/test/test_states.py b/shared/workspaces/test/capability/test_states.py
similarity index 100%
rename from shared/workspaces/test/test_states.py
rename to shared/workspaces/test/capability/test_states.py
diff --git a/shared/workspaces/test/notification/test_nothing.py b/shared/workspaces/test/notification/test_nothing.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b79f3d7c6cde773aff5ea674837f99aaad06fe3
--- /dev/null
+++ b/shared/workspaces/test/notification/test_nothing.py
@@ -0,0 +1,2 @@
+def test_always_passes():
+    assert True
diff --git a/shared/workspaces/test/workflow/__init__.py b/shared/workspaces/test/workflow/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/shared/workspaces/test/test_remote_processing_service.py b/shared/workspaces/test/workflow/test_remote_processing_service.py
similarity index 98%
rename from shared/workspaces/test/test_remote_processing_service.py
rename to shared/workspaces/test/workflow/test_remote_processing_service.py
index a48fe15d86c25d4134ac85e6f6e057c700c84427..9714856336986a441156d490bdfdae07af4b65b6 100644
--- a/shared/workspaces/test/test_remote_processing_service.py
+++ b/shared/workspaces/test/workflow/test_remote_processing_service.py
@@ -18,7 +18,7 @@
 from datetime import datetime
 from unittest.mock import patch, MagicMock
 
-from test.test_workflow_info import FakeWorkflowInfo
+from .test_workflow_info import FakeWorkflowInfo
 from workspaces.system.schema import AbstractFile
 from workspaces.workflow.services.remote_processing_service import CapoInjector
 from workspaces.workflow.schema import Workflow, WorkflowRequest
diff --git a/shared/workspaces/test/test_views.py b/shared/workspaces/test/workflow/test_views.py
similarity index 100%
rename from shared/workspaces/test/test_views.py
rename to shared/workspaces/test/workflow/test_views.py
diff --git a/shared/workspaces/test/test_workflow_architect.py b/shared/workspaces/test/workflow/test_workflow_architect.py
similarity index 100%
rename from shared/workspaces/test/test_workflow_architect.py
rename to shared/workspaces/test/workflow/test_workflow_architect.py
diff --git a/shared/workspaces/test/test_workflow_info.py b/shared/workspaces/test/workflow/test_workflow_info.py
similarity index 100%
rename from shared/workspaces/test/test_workflow_info.py
rename to shared/workspaces/test/workflow/test_workflow_info.py
diff --git a/shared/workspaces/test/test_workflow_recovery.py b/shared/workspaces/test/workflow/test_workflow_recovery.py
similarity index 97%
rename from shared/workspaces/test/test_workflow_recovery.py
rename to shared/workspaces/test/workflow/test_workflow_recovery.py
index 82334f0571f92acf2ac09c974622ab5bc780f447..f45d5c18bf9f4e452c5a323061a057caefa2dc19 100644
--- a/shared/workspaces/test/test_workflow_recovery.py
+++ b/shared/workspaces/test/workflow/test_workflow_recovery.py
@@ -25,7 +25,7 @@ from pendulum import DateTime
 
 import workspaces.workflow.services.recovery as recovery
 
-from .conftest import mock_workflow_requests
+from test.conftest import mock_workflow_requests
 
 fake_profile = "test-dev"
 
diff --git a/shared/workspaces/test/test_workflow_service.py b/shared/workspaces/test/workflow/test_workflow_service.py
similarity index 99%
rename from shared/workspaces/test/test_workflow_service.py
rename to shared/workspaces/test/workflow/test_workflow_service.py
index 4d9f37d3a01c7d56963e13c5143a30cab9000234..6eb2b9628e828b3adf03aa59286818df60b7eec3 100644
--- a/shared/workspaces/test/test_workflow_service.py
+++ b/shared/workspaces/test/workflow/test_workflow_service.py
@@ -47,7 +47,7 @@ from workspaces.workflow.services.interfaces import WorkflowInfoIF
 from workspaces.workflow.services.workflow_info import WorkflowInfo
 from workspaces.workflow.services.workflow_service import WorkflowService
 
-from .conftest import mock_workflow_service
+from test.conftest import mock_workflow_service
 
 logger = logging.getLogger(__name__)
 logger.setLevel(logging.INFO)