diff --git a/neutron_vpnaas/tests/base.py b/neutron_vpnaas/tests/base.py
index 385d46f1b..9d4d3f8aa 100644
--- a/neutron_vpnaas/tests/base.py
+++ b/neutron_vpnaas/tests/base.py
@@ -15,8 +15,8 @@
 #
 
 from neutron.tests import base as n_base
-from neutron.tests.unit import test_api_v2_extension
-from neutron.tests.unit import test_db_plugin
+from neutron.tests.unit.db import test_db_base_plugin_v2 as test_db_plugin
+from neutron.tests.unit.extensions import base as test_api_v2_extension
 
 
 class BaseTestCase(n_base.BaseTestCase):
diff --git a/neutron_vpnaas/tests/unit/db/vpn/test_db_vpnaas.py b/neutron_vpnaas/tests/unit/db/vpn/test_vpn_db.py
similarity index 99%
rename from neutron_vpnaas/tests/unit/db/vpn/test_db_vpnaas.py
rename to neutron_vpnaas/tests/unit/db/vpn/test_vpn_db.py
index 2f44d957a..eefe08ae5 100644
--- a/neutron_vpnaas/tests/unit/db/vpn/test_db_vpnaas.py
+++ b/neutron_vpnaas/tests/unit/db/vpn/test_vpn_db.py
@@ -30,8 +30,8 @@ from neutron import manager
 from neutron.openstack.common import uuidutils
 from neutron.plugins.common import constants
 from neutron.scheduler import l3_agent_scheduler
-from neutron.tests.unit import test_db_plugin
-from neutron.tests.unit import test_l3_plugin
+from neutron.tests.unit.db import test_db_base_plugin_v2 as test_db_plugin
+from neutron.tests.unit.extensions import test_l3 as test_l3_plugin
 from oslo_config import cfg
 import webob.exc
 
@@ -433,7 +433,7 @@ class VPNPluginDbTestCase(VPNTestMixin,
 
         service_plugins = {'vpnaas_plugin': vpnaas_plugin}
         plugin_str = ('neutron_vpnaas.tests.unit.db.vpn.'
-                      'test_db_vpnaas.TestVpnCorePlugin')
+                      'test_vpn_db.TestVpnCorePlugin')
 
         super(VPNPluginDbTestCase, self).setUp(
             plugin_str,
diff --git a/neutron_vpnaas/tests/unit/services/vpn/test_vpnaas_extension.py b/neutron_vpnaas/tests/unit/extensions/test_vpnaas.py
similarity index 99%
rename from neutron_vpnaas/tests/unit/services/vpn/test_vpnaas_extension.py
rename to neutron_vpnaas/tests/unit/extensions/test_vpnaas.py
index 5657bbc0d..ff26d1343 100644
--- a/neutron_vpnaas/tests/unit/services/vpn/test_vpnaas_extension.py
+++ b/neutron_vpnaas/tests/unit/extensions/test_vpnaas.py
@@ -17,7 +17,7 @@ import copy
 import mock
 from neutron.openstack.common import uuidutils
 from neutron.plugins.common import constants
-from neutron.tests.unit import test_api_v2
+from neutron.tests.unit.api.v2 import test_base as test_api_v2
 from webob import exc
 
 from neutron_vpnaas.extensions import vpnaas
diff --git a/neutron_vpnaas/tests/unit/services/vpn/common/test_agent_netns_wrapper.py b/neutron_vpnaas/tests/unit/services/vpn/common/test_netns_wrapper.py
similarity index 100%
rename from neutron_vpnaas/tests/unit/services/vpn/common/test_agent_netns_wrapper.py
rename to neutron_vpnaas/tests/unit/services/vpn/common/test_netns_wrapper.py
diff --git a/neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_cisco_csr_rest.py b/neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_cisco_csr_rest_client.py
similarity index 100%
rename from neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_cisco_csr_rest.py
rename to neutron_vpnaas/tests/unit/services/vpn/device_drivers/test_cisco_csr_rest_client.py
diff --git a/neutron_vpnaas/tests/unit/services/vpn/test_vpnaas_driver_plugin.py b/neutron_vpnaas/tests/unit/services/vpn/test_plugin.py
similarity index 97%
rename from neutron_vpnaas/tests/unit/services/vpn/test_vpnaas_driver_plugin.py
rename to neutron_vpnaas/tests/unit/services/vpn/test_plugin.py
index d09f4a7a6..57d7f93ab 100644
--- a/neutron_vpnaas/tests/unit/services/vpn/test_vpnaas_driver_plugin.py
+++ b/neutron_vpnaas/tests/unit/services/vpn/test_plugin.py
@@ -19,12 +19,12 @@ from neutron.common import constants
 from neutron import context
 from neutron import manager
 from neutron.plugins.common import constants as p_constants
-from neutron.tests.unit.openvswitch import test_agent_scheduler
-from neutron.tests.unit import test_agent_ext_plugin
+from neutron.tests.unit.extensions import test_agent as test_agent_ext_plugin
+from neutron.tests.unit.plugins.openvswitch import test_agent_scheduler
 
 from neutron_vpnaas.db.vpn import vpn_validator
 from neutron_vpnaas.services.vpn.service_drivers import ipsec as ipsec_driver
-from neutron_vpnaas.tests.unit.db.vpn import test_db_vpnaas
+from neutron_vpnaas.tests.unit.db.vpn import test_vpn_db as test_db_vpnaas
 
 FAKE_HOST = test_agent_ext_plugin.L3_HOSTA
 VPN_DRIVER_CLASS = 'neutron_vpnaas.services.vpn.plugin.VPNDriverPlugin'
diff --git a/tools/check_bash.sh b/tools/check_bash.sh
index e9d178eeb..e90c8ca6c 100644
--- a/tools/check_bash.sh
+++ b/tools/check_bash.sh
@@ -22,7 +22,7 @@
 
 # Ignore comments, but include shebangs
 OBSERVED=$(grep -E '^([^#]|#!).*bash' tox.ini tools/* | wc -l)
-EXPECTED=5
+EXPECTED=6
 if [ ${EXPECTED} -ne ${OBSERVED} ]; then
     echo Unexpected number of bash usages are detected.
     echo Please read the comment in $0
diff --git a/tools/check_unit_test_structure.sh b/tools/check_unit_test_structure.sh
new file mode 100755
index 000000000..15dcb5d6d
--- /dev/null
+++ b/tools/check_unit_test_structure.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# This script identifies the unit test modules that do not correspond
+# directly with a module in the code tree.  See TESTING.rst for the 
+# intended structure.
+
+neutron_path=$(cd "$(dirname "$0")/.." && pwd)
+base_test_path=neutron_vpnaas/tests/unit
+test_path=$neutron_path/$base_test_path
+
+test_files=$(find ${test_path} -iname 'test_*.py')
+
+ignore_regexes=(
+    "^plugins.*$"
+)
+
+error_count=0
+ignore_count=0
+total_count=0
+for test_file in ${test_files[@]}; do
+    relative_path=${test_file#$test_path/}
+    expected_path=$(dirname $neutron_path/neutron_vpnaas/$relative_path)
+    test_filename=$(basename "$test_file")
+    expected_filename=${test_filename#test_}
+    # Module filename (e.g. foo/bar.py -> foo/test_bar.py)
+    filename=$expected_path/$expected_filename
+    # Package dir (e.g. foo/ -> test_foo.py)
+    package_dir=${filename%.py}
+    if [ ! -f "$filename" ] && [ ! -d "$package_dir" ]; then
+        for ignore_regex in ${ignore_regexes[@]}; do
+            if [[ "$relative_path" =~ $ignore_regex ]]; then
+                ((ignore_count++))
+                continue 2
+            fi
+        done
+        echo "Unexpected test file: $base_test_path/$relative_path"
+        ((error_count++))
+    fi
+    ((total_count++))
+done
+
+if [ "$ignore_count" -ne 0 ]; then
+    echo "$ignore_count unmatched test modules were ignored"
+fi
+
+if [ "$error_count" -eq 0 ]; then
+    echo 'Success!  All test modules match targets in the code tree.'
+    exit 0
+else
+    echo "Failure! $error_count of $total_count test modules do not match targets in the code tree."
+    exit 1
+fi
diff --git a/tox.ini b/tox.ini
index bbe05b05c..553977ea8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -60,8 +60,7 @@ commands =
   sh ./tools/check_bash.sh
   flake8
   pylint --rcfile=.pylintrc --output-format=colorized {posargs:neutron_vpnaas}
-  #neutron-db-manage check_migration
-  #sh -c "find neutron-vpnaas -type f -regex '.*\.pot?' -print0|xargs -0 -n 1 msgfmt --check-format -o /dev/null"
+  {toxinidir}/tools/check_unit_test_structure.sh
 whitelist_externals = sh
 
 [testenv:i18n]