diff --git a/build.xml b/build.xml
index f4ae9a76ecaf66d38ac79fe007228bb688d768b6..3219f96d6f196a381fad816cfcde91d589f3304d 100644
--- a/build.xml
+++ b/build.xml
@@ -139,7 +139,7 @@
     </if>
 
     <!-- start Solr (use restart in case of old PID files) -->
-    <exec command="VUFIND_HOME=${srcdir} VUFIND_LOCAL_DIR=${srcdir}/local JETTY_PID=${tmp}/vufindtest.pid JETTY_CONSOLE=/dev/null ${srcdir}/vufind.sh restart" outputProperty="LASTOUTPUT" />
+    <exec command="VUFIND_HOME=${srcdir} VUFIND_LOCAL_DIR=${srcdir}/local JETTY_PID=${srcdir}/local/vufindtest.pid JETTY_CONSOLE=/dev/null ${srcdir}/vufind.sh restart" outputProperty="LASTOUTPUT" />
     <echo message="${LASTOUTPUT}" />
 
     <!-- wait for Solor to finish spinning up -->
@@ -178,7 +178,7 @@
     </if>
 
     <!-- stop Solr -->
-    <exec command="VUFIND_HOME=${srcdir} VUFIND_LOCAL_DIR=${srcdir}/local JETTY_PID=${tmp}/vufindtest.pid ${srcdir}/vufind.sh stop" outputProperty="LASTOUTPUT" />
+    <exec command="VUFIND_HOME=${srcdir} VUFIND_LOCAL_DIR=${srcdir}/local JETTY_PID=${srcdir}/local/vufindtest.pid ${srcdir}/vufind.sh stop" outputProperty="LASTOUTPUT" />
     <echo message="${LASTOUTPUT}" />
 
     <!-- delete the configuration, sample index, logs and cache data -->
diff --git a/module/VuFind/src/VuFindTest/Unit/TestCase.php b/module/VuFind/src/VuFindTest/Unit/TestCase.php
index 35808d258093c97becef77a3a6f3c8292282d987..6c53f6d9c75d1d369941fc2b1c1316b7ac211abc 100644
--- a/module/VuFind/src/VuFindTest/Unit/TestCase.php
+++ b/module/VuFind/src/VuFindTest/Unit/TestCase.php
@@ -245,4 +245,15 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
         }
         return $sm->get('VuFind\AuthPluginManager');
     }
+
+    /**
+     * Is this test running in a continuous integration context?
+     *
+     * @return bool
+     */
+    public function continuousIntegrationRunning()
+    {
+        // We'll assume that if the CI Solr PID is present, then CI is active:
+        return file_exists(__DIR__ . '/../../../../../local/vufindtest.pid');
+    }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Auth/DatabaseTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/Auth/DatabaseTest.php
similarity index 90%
rename from module/VuFind/tests/unit-tests/src/VuFindTest/Auth/DatabaseTest.php
rename to module/VuFind/tests/integration-tests/src/VuFindTest/Auth/DatabaseTest.php
index d6b6664e902984655b8f3ac20d35165700c2e5bb..4fde5afc0ef7b10ccfa6c0e31a985b1532c35a6c 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Auth/DatabaseTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/Auth/DatabaseTest.php
@@ -56,12 +56,31 @@ class DatabaseTest extends \VuFindTest\Unit\DbTestCase
      */
     public static function setUpBeforeClass()
     {
+        // If CI is not running, all tests were skipped, so no work is necessary:
+        $test = new DatabaseTest();
+        if (!$test->continuousIntegrationRunning()) {
+            return;
+        }
         // Fail if there are already users in the database (we don't want to run this
         // on a real system -- it's only meant for the continuous integration server)
-        $test = new DatabaseTest();
         $userTable = $test->getTable('User');
         if (count($userTable->select()) > 0) {
-            throw new \Exception('Test cannot run with pre-existing user data!');
+            return $this->markTestSkipped(
+                'Test cannot run with pre-existing user data!'
+            );
+        }
+    }
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        // Give up if we're not running in CI:
+        if (!$this->continuousIntegrationRunning()) {
+            return $this->markTestSkipped('Continuous integration not running.');
         }
     }
 
@@ -274,6 +293,12 @@ class DatabaseTest extends \VuFindTest\Unit\DbTestCase
      */
     public static function tearDownAfterClass()
     {
+        // If CI is not running, all tests were skipped, so no work is necessary:
+        $test = new DatabaseTest();
+        if (!$test->continuousIntegrationRunning()) {
+            return;
+        }
+
         // Delete test user
         $test = new DatabaseTest();
         $userTable = $test->getTable('User');
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Auth/ILSTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/Auth/ILSTest.php
similarity index 88%
rename from module/VuFind/tests/unit-tests/src/VuFindTest/Auth/ILSTest.php
rename to module/VuFind/tests/integration-tests/src/VuFindTest/Auth/ILSTest.php
index 53745533b7e063ce0a93dc2a69f25d4dde2fb219..58d9dc4354911fe1908104d387e8248a9510dc0e 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Auth/ILSTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/Auth/ILSTest.php
@@ -72,12 +72,31 @@ class ILSTest extends \VuFindTest\Unit\DbTestCase
      */
     public static function setUpBeforeClass()
     {
+        // If CI is not running, all tests were skipped, so no work is necessary:
+        $test = new ILSTest();
+        if (!$test->continuousIntegrationRunning()) {
+            return;
+        }
         // Fail if there are already users in the database (we don't want to run this
         // on a real system -- it's only meant for the continuous integration server)
-        $test = new ILSTest();
         $userTable = $test->getTable('User');
         if (count($userTable->select()) > 0) {
-            throw new \Exception('Test cannot run with pre-existing user data!');
+            return $this->markTestSkipped(
+                'Test cannot run with pre-existing user data!'
+            );
+        }
+    }
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        // Give up if we're not running in CI:
+        if (!$this->continuousIntegrationRunning()) {
+            return $this->markTestSkipped('Continuous integration not running.');
         }
     }
 
@@ -176,6 +195,12 @@ class ILSTest extends \VuFindTest\Unit\DbTestCase
      */
     public static function tearDownAfterClass()
     {
+        // If CI is not running, all tests were skipped, so no work is necessary:
+        $test = new ILSTest();
+        if (!$test->continuousIntegrationRunning()) {
+            return;
+        }
+
         // Delete test user
         $test = new ILSTest();
         $userTable = $test->getTable('User');
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Auth/ShibbolethTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/Auth/ShibbolethTest.php
similarity index 89%
rename from module/VuFind/tests/unit-tests/src/VuFindTest/Auth/ShibbolethTest.php
rename to module/VuFind/tests/integration-tests/src/VuFindTest/Auth/ShibbolethTest.php
index 0041224dd6d83ae5d216b369cbbe1150c8c86d0c..3b8d28e8ae7d088653b5fda11b90a71f9b5daef9 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Auth/ShibbolethTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/Auth/ShibbolethTest.php
@@ -46,12 +46,31 @@ class ShibbolethTest extends \VuFindTest\Unit\DbTestCase
      */
     public static function setUpBeforeClass()
     {
+        // If CI is not running, all tests were skipped, so no work is necessary:
+        $test = new ShibbolethTest();
+        if (!$test->continuousIntegrationRunning()) {
+            return;
+        }
         // Fail if there are already users in the database (we don't want to run this
         // on a real system -- it's only meant for the continuous integration server)
-        $test = new ShibbolethTest();
         $userTable = $test->getTable('User');
         if (count($userTable->select()) > 0) {
-            throw new \Exception('Test cannot run with pre-existing user data!');
+            return $this->markTestSkipped(
+                'Test cannot run with pre-existing user data!'
+            );
+        }
+    }
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        // Give up if we're not running in CI:
+        if (!$this->continuousIntegrationRunning()) {
+            return $this->markTestSkipped('Continuous integration not running.');
         }
     }
 
@@ -215,8 +234,13 @@ class ShibbolethTest extends \VuFindTest\Unit\DbTestCase
      */
     public static function tearDownAfterClass()
     {
-        // Delete test user
+        // If CI is not running, all tests were skipped, so no work is necessary:
         $test = new ShibbolethTest();
+        if (!$test->continuousIntegrationRunning()) {
+            return;
+        }
+
+        // Delete test user
         $userTable = $test->getTable('User');
         $user = $userTable->getByUsername('testuser', false);
         if (empty($user)) {
diff --git a/module/VuFind/tests/integration-tests/src/VuFindTest/Connection/SolrTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/Connection/SolrTest.php
index 67a4a9fdc298ef1a9d8d74d120680caafbb74094..e114f441cbbd2638ef735378b20c5771327bcbda 100644
--- a/module/VuFind/tests/integration-tests/src/VuFindTest/Connection/SolrTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/Connection/SolrTest.php
@@ -38,6 +38,19 @@ namespace VuFindTest\Integration\Connection;
  */
 class SolrTest extends \VuFindTest\Unit\TestCase
 {
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        // Give up if we're not running in CI:
+        if (!$this->continuousIntegrationRunning()) {
+            return $this->markTestSkipped('Continuous integration not running.');
+        }
+    }
+
     /**
      * Check AlphaBrowse "see also" functionality.
      *
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Db/Table/ChangeTrackerTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/Db/Table/ChangeTrackerTest.php
similarity index 92%
rename from module/VuFind/tests/unit-tests/src/VuFindTest/Db/Table/ChangeTrackerTest.php
rename to module/VuFind/tests/integration-tests/src/VuFindTest/Db/Table/ChangeTrackerTest.php
index 20d1db89cfaf9cbabc5f67693626d8d6ce3cd189..10f3900a30d16abc10f5b50609e6a031ca98c3f5 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Db/Table/ChangeTrackerTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/Db/Table/ChangeTrackerTest.php
@@ -39,6 +39,19 @@ use VuFind\Db\Table\ChangeTracker;
  */
 class ChangeTrackerTest extends \VuFindTest\Unit\DbTestCase
 {
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        // Give up if we're not running in CI:
+        if (!$this->continuousIntegrationRunning()) {
+            return $this->markTestSkipped('Continuous integration not running.');
+        }
+    }
+
     /**
      * Test change tracking
      *
diff --git a/module/VuFind/tests/integration-tests/src/VuFindTest/View/Helper/Root/ResultFeedTest.php b/module/VuFind/tests/integration-tests/src/VuFindTest/View/Helper/Root/ResultFeedTest.php
index 4dcc545c81a9a36b36e03b60b1cdbf4f905ee0a3..cbcc6095574b6cd8a1e37924b9c8e608ab43a404 100644
--- a/module/VuFind/tests/integration-tests/src/VuFindTest/View/Helper/Root/ResultFeedTest.php
+++ b/module/VuFind/tests/integration-tests/src/VuFindTest/View/Helper/Root/ResultFeedTest.php
@@ -39,6 +39,19 @@ use VuFind\View\Helper\Root\ResultFeed;
  */
 class ResultFeedTest extends \VuFindTest\Unit\ViewHelperTestCase
 {
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        // Give up if we're not running in CI:
+        if (!$this->continuousIntegrationRunning()) {
+            return $this->markTestSkipped('Continuous integration not running.');
+        }
+    }
+
     /**
      * Get plugins to register to support view helper being tested
      *