diff --git a/share/spack/qa/check_dependencies b/share/spack/qa/check_dependencies
new file mode 100755
index 0000000000000000000000000000000000000000..cbcda0ce0f3fb542defda327341c1abcbb96d808
--- /dev/null
+++ b/share/spack/qa/check_dependencies
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+#
+# Description:
+#     Check to see if dependencies are installed.
+#     If not, warn the user and tell them how to
+#     install these dependencies.
+#
+# Usage:
+#     check-deps <dep> ...
+#
+# Options:
+#     One or more dependencies. Must use name of binary.
+
+for dep in "$@"; do
+    if ! which $dep &> /dev/null; then
+        # sphinx-build comes from sphinx
+        package=$(echo $dep | cut -d - -f 1)
+
+        cat << EOF
+ERROR: $package is required to run this script.
+
+To install with Spack, run:
+    $ spack install py-$package
+or, to install with pip, run:
+    $ pip install $package
+Then add the bin directory to your PATH.
+EOF
+        exit 1
+    fi
+done
+
+echo "Dependencies found."
diff --git a/share/spack/qa/run-doc-tests b/share/spack/qa/run-doc-tests
index 2be5793d369403b76da6edb376d51d9e0d17fa77..bde30f74cc02aa1741c0137e8e0fb8c3f5e55962 100755
--- a/share/spack/qa/run-doc-tests
+++ b/share/spack/qa/run-doc-tests
@@ -9,32 +9,37 @@
 #     run-doc-tests
 #
 # Notes:
-#     Requires sphinx. Can be installed by running:
-#         `spack install py-sphinx`
-#     or:
-#         `pip install sphinx`
-#     and adding the bin directory to your PATH.
+#     Requires sphinx and mercurial.
 #
 
 QA_DIR="$(dirname "$0")"
 SPACK_ROOT="$QA_DIR/../../.."
 DOC_DIR="$SPACK_ROOT/lib/spack/docs"
 
-# Move to documentation directory
-# Allows script to be run from anywhere
-cd "$DOC_DIR"
+# Array of dependencies
+deps=(
+    sphinx-build
+    hg
+)
+
+# Check for dependencies
+"$QA_DIR/check_dependencies" "${deps[@]}" || exit 1
 
 # Gather array of changed files
 changed=($("$QA_DIR/changed_files" lib/spack/docs))
 
+# Move to documentation directory
+# Allows script to be run from anywhere
+cd "$DOC_DIR"
+
 # Cleanup temporary files upon exit or when script is killed
-trap 'make clean' EXIT SIGINT SIGTERM
+trap 'make clean --silent' EXIT SIGINT SIGTERM
 
 # Only run tests if documentation was updated
 if [[ "${changed[@]}" ]]; then
     # Treat warnings as fatal errors
     make SPHINXOPTS=-W
 else
-    echo No documentation was modified.
+    echo "No documentation was modified."
 fi
 
diff --git a/share/spack/qa/run-flake8-tests b/share/spack/qa/run-flake8-tests
index 6c7b4f2c796f47ddedd57603a3b2cadf4c5c20d2..350ef3161f662409b6a393f5f6a329f627ed768b 100755
--- a/share/spack/qa/run-flake8-tests
+++ b/share/spack/qa/run-flake8-tests
@@ -9,23 +9,20 @@
 #     run-flake8-tests
 #
 # Notes:
-#     Requires flake8. Can be installed by running:
-#         `spack install py-flake8`
-#     or:
-#         `pip install flake8`
-#     and adding the bin directory to your PATH.
+#     Requires flake8.
 #
 
-# Check for dependencies
-flake8="$(which flake8)"
-if [[ ! $flake8 ]]; then
-    echo "ERROR: flake8 is required to run this script."
-    exit 1
-fi
-
 QA_DIR="$(dirname "$0")"
 SPACK_ROOT="$QA_DIR/../../.."
 
+# Array of dependencies
+deps=(
+    flake8
+)
+
+# Check for dependencies
+"$QA_DIR/check_dependencies" "${deps[@]}" || exit 1
+
 # Move to root directory of Spack
 # Allows script to be run from anywhere
 cd "$SPACK_ROOT"
@@ -33,6 +30,12 @@ cd "$SPACK_ROOT"
 # Gather array of changed files
 changed=($("$QA_DIR/changed_files" "*.py"))
 
+# Exit if no Python files were modified
+if [[ ! "${changed[@]}" ]]; then
+    echo "No Python files were modified."
+    exit 0
+fi
+
 function cleanup {
     # Restore original package files after modifying them.
     for file in "${changed[@]}"; do
@@ -55,15 +58,15 @@ for file in "${changed[@]}"; do
     #
     if [[ $file = *package.py ]]; then
         # Exempt lines with urls and descriptions from overlong line errors.
-        perl -i -pe 's/^(\s*homepage\s*=.*)$/\1  # NOQA: ignore=E501/' $file
-        perl -i -pe 's/^(\s*url\s*=.*)$/\1  # NOQA: ignore=E501/' $file
-        perl -i -pe 's/^(\s*version\(.*\).*)$/\1  # NOQA: ignore=E501/' $file
-        perl -i -pe 's/^(\s*variant\(.*\).*)$/\1  # NOQA: ignore=E501/' $file
-        perl -i -pe 's/^(\s*depends_on\(.*\).*)$/\1  # NOQA: ignore=E501/' $file
-        perl -i -pe 's/^(\s*extends\(.*\).*)$/\1  # NOQA: ignore=E501/' $file
+        perl -i -pe 's/^(\s*homepage\s*=.*)$/\1  # NOQA: ignore=E501/' "$file"
+        perl -i -pe 's/^(\s*url\s*=.*)$/\1  # NOQA: ignore=E501/' "$file"
+        perl -i -pe 's/^(\s*version\(.*\).*)$/\1  # NOQA: ignore=E501/' "$file"
+        perl -i -pe 's/^(\s*variant\(.*\).*)$/\1  # NOQA: ignore=E501/' "$file"
+        perl -i -pe 's/^(\s*depends_on\(.*\).*)$/\1  # NOQA: ignore=E501/' "$file"
+        perl -i -pe 's/^(\s*extends\(.*\).*)$/\1  # NOQA: ignore=E501/' "$file"
 
         # Exempt '@when' decorated functions from redefinition errors.
-        perl -i -pe 's/^(\s*\@when\(.*\).*)$/\1  # NOQA: ignore=F811/' $file
+        perl -i -pe 's/^(\s*\@when\(.*\).*)$/\1  # NOQA: ignore=F811/' "$file"
     fi
 
     #
@@ -72,21 +75,15 @@ for file in "${changed[@]}"; do
     perl -i -pe 's/^(.*(https?|file)\:.*)$/\1  # NOQA: ignore=E501/' $file
 done
 
-if [[ "${changed[@]}" ]]; then
-    echo =======================================================
-    echo  flake8: running flake8 code checks on spack.
-    echo
-    echo  Modified files:
-    echo  "${changed[@]}" | perl -pe 's/^/  /;s/ +/\n  /g'
-    echo =======================================================
-    if flake8 --format pylint "${changed[@]}"; then
-        echo "Flake8 checks were clean."
-    else
-        echo "Flake8 found errors."
-        exit 1
-    fi
+echo =======================================================
+echo  flake8: running flake8 code checks on spack.
+echo
+echo  Modified files:
+echo  "${changed[@]}" | perl -pe 's/^/  /;s/ +/\n  /g'
+echo =======================================================
+if flake8 --format pylint "${changed[@]}"; then
+    echo "Flake8 checks were clean."
 else
-    echo No Python files were modified.
+    echo "Flake8 found errors."
+    exit 1
 fi
-
-exit 0
diff --git a/share/spack/qa/run-unit-tests b/share/spack/qa/run-unit-tests
index 33fb1bfae2a992378c0da0e1ec319d050b69ce6f..9ce3062e58f4655ba7723e97d91081d00bb67197 100755
--- a/share/spack/qa/run-unit-tests
+++ b/share/spack/qa/run-unit-tests
@@ -1,20 +1,60 @@
 #!/usr/bin/env bash
 #
-# This script runs Spack unit tests.
+# Description:
+#     Runs Spack unit tests.
 #
-# It should be executed from the top-level directory of the repo,
-# e.g.:
+# Usage:
+#     run-unit-tests [test ...]
 #
-#    share/spack/qa/run-unit-tests
+# Options:
+#     Optionally add one or more unit tests
+#     to only run these tests.
 #
-# To run it, you'll need to have the Python coverage installed locally.
+# Notes:
+#     Requires coverage.
 #
 
-# Regular spack setup and tests
-. ./share/spack/setup-env.sh
+QA_DIR="$(dirname "$0")"
+SPACK_ROOT="$QA_DIR/../../.."
+
+# Array of dependencies
+deps=(
+    coverage
+)
+
+# Check for dependencies
+"$QA_DIR/check_dependencies" "${deps[@]}" || exit 1
+
+# Add Spack to the PATH.
+export PATH="$SPACK_ROOT/bin:$PATH"
+
+# Array of directories containing core Spack framework
+core_dirs=(
+    bin
+    etc
+    # lib, but skip documentation
+    lib/spack/env
+    lib/spack/external
+    lib/spack/llnl
+    lib/spack/spack
+    share
+)
+
+# Gather array of changed files
+changed=($("$QA_DIR/changed_files" "${core_dirs[@]}"))
+
+# Exit if no core Spack framework files were modified
+if [[ ! "${changed[@]}" ]]; then
+    echo "No core Spack framework files were modified."
+    exit 0
+fi
+
+# Run integration tests
+# TODO: should these be separated into a different test suite?
+source "$SPACK_ROOT/share/spack/setup-env.sh"
 spack compilers
 spack config get compilers
 spack install -v libdwarf
 
 # Run unit tests with code coverage
-coverage run bin/spack test
+coverage run spack test "$@"