From e5f86d6efeff6756c1cf66c953f2eacfd1dc59a7 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Sun, 25 Oct 2020 14:44:29 -0400
Subject: [PATCH] Simplify PHPUnit fixture handling. (#1766)

- Create trait to centralize fixture loading
- Eliminate unnecessary constants used by test process
- Reduce usage of hard-to-read relative paths
---
 .../src/VuFindTest/Unit/FixtureTrait.php      |  90 ++++++++++++++++++
 module/VuFind/tests/bootstrap.php             |   5 -
 .../Config/SearchSpecsReaderTest.php          |  10 +-
 .../src/VuFindTest/Config/UpgradeTest.php     |   8 +-
 .../src/VuFindTest/Config/VersionTest.php     |   4 +-
 .../src/VuFindTest/Config/WriterTest.php      |   9 +-
 .../VuFindTest/Connection/WikipediaTest.php   |   5 +-
 .../Connection/WorldCatUtilsTest.php          |   5 +-
 .../VuFindTest/Content/PageLocatorTest.php    |  41 +++-----
 .../ContentBlock/TemplateBasedTest.php        |   4 +-
 .../src/VuFindTest/DoiLinker/BrowZineTest.php |   8 +-
 .../VuFindTest/DoiLinker/UnpaywallTest.php    |  20 ++--
 .../src/VuFindTest/Form/FormTest.php          |   8 +-
 .../Translator/Loader/ExtendedIniTest.php     |  14 +--
 .../src/VuFindTest/ILS/Driver/DAIATest.php    |  14 +--
 .../src/VuFindTest/ILS/Driver/FolioTest.php   |  15 +--
 .../src/VuFindTest/ILS/Driver/PAIATest.php    |  14 +--
 .../src/VuFindTest/ILS/Driver/XCNCIP2Test.php |  14 +--
 .../Recommend/EuropeanaResultsTest.php        |  15 +--
 .../Recommend/RandomRecommendTest.php         |  15 +--
 .../RecordDriver/DefaultRecordTest.php        |  12 +--
 .../RecordDriver/SolrDefaultTest.php          |  12 +--
 .../VuFindTest/RecordDriver/SolrMarcTest.php  |  29 ++----
 .../src/VuFindTest/Reserves/CsvReaderTest.php |  18 +---
 .../VuFindTest/Resolver/Driver/AlmaTest.php   |  14 +--
 .../VuFindTest/Resolver/Driver/EzbTest.php    |  14 +--
 .../VuFindTest/Resolver/Driver/RediTest.php   |  14 +--
 .../VuFindTest/Search/QueryAdapterTest.php    |  18 ++--
 .../Search/Solr/SpellingProcessorTest.php     |  35 +++----
 .../Search/Solr/V3/ErrorListenerTest.php      |  14 +--
 .../Search/Solr/V4/ErrorListenerTest.php      |  14 +--
 .../VuFindTest/Search/UrlQueryHelperTest.php  |   5 +-
 .../View/Helper/Root/OpenUrlTest.php          |  43 ++-------
 .../Helper/Root/RecordDataFormatterTest.php   |  11 +--
 .../View/Helper/Root/RecordTest.php           |  11 +--
 .../Generate/DynamicRouteCommandTest.php      |   4 +-
 .../NonTabRecordActionCommandTest.php         |   4 +-
 .../Generate/RecordRouteCommandTest.php       |   4 +-
 .../Generate/StaticRouteCommandTest.php       |   4 +-
 .../Command/Harvest/MergeMarcCommandTest.php  |   6 +-
 .../Command/Import/WebCrawlCommandTest.php    |   6 +-
 .../Language/AddUsingTemplateCommandTest.php  |  14 ++-
 .../Language/CopyStringCommandTest.php        |  14 ++-
 .../Command/Language/DeleteCommandTest.php    |  14 ++-
 .../Command/Language/NormalizeCommandTest.php |  14 ++-
 .../Command/Util/DedupeCommandTest.php        |   6 +-
 .../Command/Util/DeletesCommandTest.php       |   4 +-
 .../Command/Util/IndexReservesCommandTest.php |   6 +-
 .../fixtures/browzine/response/search         | Bin
 .../fixtures/eds/query/advanced               | Bin
 .../fixtures/eds/response/autocomplete        |   0
 .../fixtures/eds/response/retrieve            |   0
 .../fixtures/eds/response/search              |   0
 .../fixtures/eit/query/advanced               | Bin
 .../fixtures/eit/response/retrieve            |   0
 .../fixtures/eit/response/search              |   0
 .../fixtures/libguides/response/search        | Bin
 .../fixtures/pazpar2/response/pp2search       |   0
 .../fixtures/pazpar2/response/pp2show         |   0
 .../primo/response/error-with-success-http    |   0
 .../fixtures/primo/response/record-http       |   0
 .../fixtures/primo/response/retrieve          |   0
 .../fixtures/primo/response/search            |   0
 .../fixtures/primo/response/search-http       |   0
 .../primo/response/swansea-search-http        |   0
 .../fixtures/searchspecs.yaml                 |   0
 .../fixtures/solr/response/bad-request        |   0
 .../solr/response/internal-server-error       |   0
 .../fixtures/solr/response/morelikethis       |   0
 .../fixtures/solr/response/multi-record       |   0
 .../fixtures/solr/response/multi-record-part1 |   0
 .../fixtures/solr/response/multi-record-part2 |   0
 .../fixtures/solr/response/multi-record-part3 |   0
 .../fixtures/solr/response/no-match           |   0
 .../fixtures/solr/response/single-record      |   0
 .../fixtures/solr/response/terms              |   0
 .../fixtures/summon/query/advanced            | Bin
 .../fixtures/summon/query/basic               | Bin
 .../fixtures/summon/response/retrieve1        |   0
 .../fixtures/summon/response/retrieve2        |   0
 .../fixtures/summon/response/search           |   0
 .../fixtures/summon/response/single-record    |   0
 .../fixtures/worldcat/query/advanced          | Bin
 .../fixtures/worldcat/query/basic             | Bin
 .../fixtures/worldcat/response/search         |   0
 .../fixtures/worldcat/response/single-record  |   0
 .../Backend/BrowZine/BackendTest.php          |  25 +----
 .../VuFindTest/Backend/EDS/BackendTest.php    |  10 +-
 .../Backend/EDS/QueryBuilderTest.php          |   8 +-
 .../VuFindTest/Backend/EIT/BackendTest.php    |   8 +-
 .../Backend/EIT/QueryBuilderTest.php          |   6 +-
 .../Backend/LibGuides/BackendTest.php         |  25 +----
 .../Backend/Pazpar2/BackendTest.php           |   9 +-
 .../VuFindTest/Backend/Primo/BackendTest.php  |  10 +-
 .../Backend/Primo/ConnectorTest.php           |   8 +-
 .../VuFindTest/Backend/Solr/BackendTest.php   |  10 +-
 .../VuFindTest/Backend/Solr/ConnectorTest.php |   9 +-
 .../VuFindTest/Backend/Summon/BackendTest.php |  10 +-
 .../Backend/Summon/QueryBuilderTest.php       |   6 +-
 .../Backend/WorldCat/BackendTest.php          |  10 +-
 .../Backend/WorldCat/QueryBuilderTest.php     |   8 +-
 .../fixtures/themes/child/child.txt           |   0
 .../fixtures/themes/child/css/child.css       |   0
 .../fixtures/themes/child/js/extra.js         |   0
 .../fixtures/themes/child/js/hello.js         |   0
 .../fixtures/themes/child/theme.config.php    |   0
 .../fixtures/themes/mixin/js/hello.js         |   0
 .../fixtures/themes/mixin/js/mixin.js         |   0
 .../fixtures/themes/mixin/mixin.config.php    |   0
 .../themes/mixin_user/theme.config.php        |   0
 .../fixtures/themes/parent/js/hello.js        |   0
 .../fixtures/themes/parent/parent.txt         |   0
 .../themes/parent/templates/everything.phtml  |   0
 .../templates/page-locator-test/page1.md      |   0
 .../templates/page-locator-test/page1.phtml   |   0
 .../page-locator-test/page2_aa.phtml          |   0
 .../page-locator-test/page2_bb.phtml          |   0
 .../templates/page-locator-test/page3.phtml   |   0
 .../page-locator-test/page3_bb.phtml          |   0
 .../templates/page-locator-test/page4.md      |   0
 .../templates/page-locator-test/page5_aa.md   |   0
 .../templates/page-locator-test/page5_bb.md   |   0
 .../templates/page-locator-test/page6.md      |   0
 .../templates/page-locator-test/page6_bb.md   |   0
 .../fixtures/themes/parent/theme.config.php   |   0
 .../src/VuFindTest/ThemeCompilerTest.php      |  12 +--
 .../src/VuFindTest/ThemeInfoTest.php          |   5 +-
 .../View/Helper/ParentTemplateTest.php        |   5 +-
 .../View/Helper/TemplatePathTest.php          |   5 +-
 129 files changed, 419 insertions(+), 452 deletions(-)
 create mode 100644 module/VuFind/src/VuFindTest/Unit/FixtureTrait.php
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/browzine/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eds/query/advanced (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eds/response/autocomplete (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eds/response/retrieve (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eds/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eit/query/advanced (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eit/response/retrieve (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/eit/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/libguides/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/pazpar2/response/pp2search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/pazpar2/response/pp2show (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/primo/response/error-with-success-http (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/primo/response/record-http (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/primo/response/retrieve (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/primo/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/primo/response/search-http (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/primo/response/swansea-search-http (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/searchspecs.yaml (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/bad-request (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/internal-server-error (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/morelikethis (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/multi-record (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/multi-record-part1 (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/multi-record-part2 (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/multi-record-part3 (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/no-match (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/single-record (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/solr/response/terms (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/summon/query/advanced (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/summon/query/basic (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/summon/response/retrieve1 (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/summon/response/retrieve2 (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/summon/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/summon/response/single-record (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/worldcat/query/advanced (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/worldcat/query/basic (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/worldcat/response/search (100%)
 rename module/VuFindSearch/tests/{unit-tests => }/fixtures/worldcat/response/single-record (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/child/child.txt (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/child/css/child.css (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/child/js/extra.js (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/child/js/hello.js (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/child/theme.config.php (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/mixin/js/hello.js (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/mixin/js/mixin.js (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/mixin/mixin.config.php (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/mixin_user/theme.config.php (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/js/hello.js (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/parent.txt (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/everything.phtml (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page1.md (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page1.phtml (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page2_aa.phtml (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page2_bb.phtml (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page3.phtml (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page3_bb.phtml (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page4.md (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page5_aa.md (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page5_bb.md (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page6.md (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/templates/page-locator-test/page6_bb.md (100%)
 rename module/VuFindTheme/tests/{unit-tests => }/fixtures/themes/parent/theme.config.php (100%)

diff --git a/module/VuFind/src/VuFindTest/Unit/FixtureTrait.php b/module/VuFind/src/VuFindTest/Unit/FixtureTrait.php
new file mode 100644
index 00000000000..1aac9193de6
--- /dev/null
+++ b/module/VuFind/src/VuFindTest/Unit/FixtureTrait.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Trait adding functionality for loading fixtures.
+ *
+ * PHP version 7
+ *
+ * Copyright (C) Villanova University 2020.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+namespace VuFindTest\Unit;
+
+use RuntimeException;
+
+/**
+ * Trait adding functionality for loading fixtures.
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+trait FixtureTrait
+{
+    /**
+     * Get the base directory containing fixtures.
+     *
+     * @param string $module Module containing fixture.
+     *
+     * @return string
+     */
+    protected function getFixtureDir($module = 'VuFind')
+    {
+        return __DIR__ . '/../../../../' . $module . '/tests/fixtures/';
+    }
+
+    /**
+     * Load a fixture file.
+     *
+     * @param string $filename Filename relative to fixture directory.
+     * @param string $module   Module containing fixture.
+     *
+     * @return string
+     * @throws RuntimeException
+     */
+    protected function getFixture($filename, $module = 'VuFind')
+    {
+        $realFilename = realpath($this->getFixtureDir($module) . $filename);
+        if (!$realFilename || !file_exists($realFilename)
+            || !is_readable($realFilename)
+        ) {
+            throw new RuntimeException(
+                sprintf('Unable to resolve fixture to fixture file: %s', $filename)
+            );
+        }
+        return file_get_contents($realFilename);
+    }
+
+    /**
+     * Load a JSON fixture from file (using associative array return type).
+     *
+     * @param string $filename Filename relative to fixture directory.
+     * @param string $module   Module containing fixture.
+     *
+     * @return array
+     */
+    protected function getJsonFixture($filename, $module = 'VuFind')
+    {
+        return json_decode($this->getFixture($filename, $module), true);
+    }
+}
diff --git a/module/VuFind/tests/bootstrap.php b/module/VuFind/tests/bootstrap.php
index 05bef2d6ab8..571aecd1666 100644
--- a/module/VuFind/tests/bootstrap.php
+++ b/module/VuFind/tests/bootstrap.php
@@ -1,8 +1,5 @@
 <?php
 
-// Set path to this module
-define('VUFIND_PHPUNIT_MODULE_PATH', __DIR__);
-
 // Define path to application directory
 defined('APPLICATION_PATH')
     || define(
@@ -64,5 +61,3 @@ if (file_exists('vendor/autoload.php')) {
     }
     $loader->register();
 }
-
-define('PHPUNIT_SEARCH_FIXTURES', realpath(__DIR__ . '/../../VuFindSearch/tests/unit-tests/fixtures'));
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php
index ca4ebc48210..60c12993870 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php
@@ -42,6 +42,8 @@ use VuFind\Config\SearchSpecsReader;
  */
 class SearchSpecsReaderTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Flag -- did writing config files fail?
      *
@@ -122,8 +124,8 @@ class SearchSpecsReaderTest extends \VuFindTest\Unit\TestCase
     public function testYamlLoad()
     {
         $reader = new SearchSpecsReader();
-        $core = __DIR__ . '/../../../../fixtures/configs/yaml/core.yaml';
-        $local = __DIR__ . '/../../../../fixtures/configs/yaml/local.yaml';
+        $core = $this->getFixtureDir() . 'configs/yaml/core.yaml';
+        $local = $this->getFixtureDir() . 'configs/yaml/local.yaml';
         $this->assertEquals(
             [
                 'top' => ['foo' => 'bar'],
@@ -148,8 +150,8 @@ class SearchSpecsReaderTest extends \VuFindTest\Unit\TestCase
     public function testYamlMerge()
     {
         $reader = new SearchSpecsReader();
-        $core = __DIR__ . '/../../../../fixtures/configs/yaml/core.yaml';
-        $local = __DIR__ . '/../../../../fixtures/configs/yaml/local.yaml';
+        $core = $this->getFixtureDir() . 'configs/yaml/core.yaml';
+        $local = $this->getFixtureDir() . 'configs/yaml/local.yaml';
         $this->assertEquals(
             [
                 'top' => ['foo' => 'xyzzy'],
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php
index 4914e862e98..c95afffbafc 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/UpgradeTest.php
@@ -41,6 +41,8 @@ use VuFind\Config\Upgrade;
  */
 class UpgradeTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Target upgrade version
      *
@@ -57,7 +59,7 @@ class UpgradeTest extends \VuFindTest\Unit\TestCase
      */
     protected function getUpgrader($version)
     {
-        $oldDir = realpath(__DIR__ . '/../../../../fixtures/configs/' . $version);
+        $oldDir = realpath($this->getFixtureDir() . 'configs/' . $version);
         $rawDir = realpath(__DIR__ . '/../../../../../../../config/vufind');
         return new Upgrade($version, $this->targetVersion, $oldDir, $rawDir);
     }
@@ -469,7 +471,7 @@ class UpgradeTest extends \VuFindTest\Unit\TestCase
     {
         $upgrader = $this->getUpgrader('1.4');
         $meaningless = realpath(
-            __DIR__ . '/../../../../fixtures/configs/solrmarc/empty.properties'
+            $this->getFixtureDir() . 'configs/solrmarc/empty.properties'
         );
         $this->assertFalse(
             $this->callMethod(
@@ -477,7 +479,7 @@ class UpgradeTest extends \VuFindTest\Unit\TestCase
             )
         );
         $meaningful = realpath(
-            __DIR__ . '/../../../../fixtures/configs/solrmarc/meaningful.properties'
+            $this->getFixtureDir() . 'configs/solrmarc/meaningful.properties'
         );
         $this->assertTrue(
             $this->callMethod(
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/VersionTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/VersionTest.php
index a4d73ad9265..1c72d62afea 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/VersionTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/VersionTest.php
@@ -41,6 +41,8 @@ use VuFind\Config\Version;
  */
 class VersionTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test the default directory parameter.
      *
@@ -75,7 +77,7 @@ class VersionTest extends \VuFindTest\Unit\TestCase
      */
     public function testKnownVersion()
     {
-        $fixture = __DIR__ . '/../../../../fixtures/configs/buildxml-2.5';
+        $fixture = $this->getFixtureDir() . 'configs/buildxml-2.5';
         $this->assertEquals('2.5', Version::getBuildVersion($fixture));
     }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/WriterTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/WriterTest.php
index 698bcbb26e4..05b94d6fdda 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/WriterTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/WriterTest.php
@@ -41,6 +41,8 @@ use VuFind\Config\Writer;
  */
 class WriterTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test reading from a file.
      *
@@ -48,9 +50,10 @@ class WriterTest extends \VuFindTest\Unit\TestCase
      */
     public function testReadFile()
     {
-        $file = realpath(__DIR__ . '/../../../../fixtures/configs/1.1/sms.ini');
-        $test = new Writer($file);
-        $this->assertEquals(file_get_contents($file), $test->getContent());
+        $test = new Writer($this->getFixtureDir() . 'configs/1.1/sms.ini');
+        $this->assertEquals(
+            $this->getFixture('configs/1.1/sms.ini'), $test->getContent()
+        );
     }
 
     /**
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WikipediaTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WikipediaTest.php
index 28048abe0e6..08c61c7e0f3 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WikipediaTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WikipediaTest.php
@@ -44,6 +44,8 @@ use VuFind\Connection\Wikipedia;
  */
 class WikipediaTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test processing of English-language Jane Austen entry.
      *
@@ -68,9 +70,8 @@ class WikipediaTest extends \PHPUnit\Framework\TestCase
      */
     protected function getClient($fixture)
     {
-        $file = realpath(__DIR__ . '/../../../../fixtures/wikipedia/' . $fixture);
         $adapter = new TestAdapter();
-        $adapter->setResponse(file_get_contents($file));
+        $adapter->setResponse($this->getFixture("wikipedia/$fixture"));
         $client = new HttpClient();
         $client->setAdapter($adapter);
         return $client;
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WorldCatUtilsTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WorldCatUtilsTest.php
index 23d3915fe52..245f032fec6 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WorldCatUtilsTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Connection/WorldCatUtilsTest.php
@@ -44,6 +44,8 @@ use VuFind\Connection\WorldCatUtils;
  */
 class WorldCatUtilsTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test related identities
      *
@@ -82,8 +84,7 @@ class WorldCatUtilsTest extends \PHPUnit\Framework\TestCase
         $client = new HttpClient();
         if (null !== $fixture) {
             $adapter = new TestAdapter();
-            $file = realpath(__DIR__ . '/../../../../fixtures/worldcat/' . $fixture);
-            $adapter->setResponse(file_get_contents($file));
+            $adapter->setResponse($this->getFixture("worldcat/$fixture"));
             $client->setAdapter($adapter);
         }
         return new WorldCatUtils('dummy', $client, $silent);
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Content/PageLocatorTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Content/PageLocatorTest.php
index 578830b1282..9e2592aca20 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Content/PageLocatorTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Content/PageLocatorTest.php
@@ -42,32 +42,25 @@ use VuFindTheme\ThemeInfo;
  */
 class PageLocatorTest extends \VuFindTest\Unit\TestCase
 {
-    /**
-     * Path to theme fixtures
-     *
-     * @var string
-     */
-    protected $fixturePath;
+    use \VuFindTest\Unit\FixtureTrait;
 
     /**
-     * Constructor
+     * Test determining a template and renderer.
+     *
+     * @return void
      */
-    public function setUp(): void
-    {
-        $this->fixturePath = realpath(__DIR__ . '/../../../../../../VuFindTheme/tests/unit-tests/fixtures/themes');
-    }
-
     public function testDetermineTemplateAndRenderer()
     {
         $language  = 'aa';
         $defaultLanguage = 'bb';
         $pathPrefix = 'templates/page-locator-test/';
+        $fixturePath = $this->getFixtureDir('VuFindTheme') . 'themes/';
         $testCases = [
             [
                 'pageName' => 'page1',
                 'result' => [
                     'renderer' => 'phtml',
-                    'path' => $this->fixturePath . '/parent/templates/page-locator-test/page1.phtml',
+                    'path' => $fixturePath . 'parent/templates/page-locator-test/page1.phtml',
                     'page' => 'page1',
                 ],
             ],
@@ -75,7 +68,7 @@ class PageLocatorTest extends \VuFindTest\Unit\TestCase
                 'pageName' => 'page2',
                 'result' => [
                     'renderer' => 'phtml',
-                    'path' => $this->fixturePath . '/parent/templates/page-locator-test/page2_aa.phtml',
+                    'path' => $fixturePath . 'parent/templates/page-locator-test/page2_aa.phtml',
                     'page' => 'page2_aa',
                 ],
             ],
@@ -83,7 +76,7 @@ class PageLocatorTest extends \VuFindTest\Unit\TestCase
                 'pageName' => 'page3',
                 'result' => [
                     'renderer' => 'phtml',
-                    'path' => $this->fixturePath . '/parent/templates/page-locator-test/page3_bb.phtml',
+                    'path' => $fixturePath . 'parent/templates/page-locator-test/page3_bb.phtml',
                     'page' => 'page3_bb',
                 ],
             ],
@@ -91,7 +84,7 @@ class PageLocatorTest extends \VuFindTest\Unit\TestCase
                 'pageName' => 'page4',
                 'result' => [
                     'renderer' => 'md',
-                    'path' => $this->fixturePath . '/parent/templates/page-locator-test/page4.md',
+                    'path' => $fixturePath . 'parent/templates/page-locator-test/page4.md',
                     'page' => 'page4',
                 ],
             ],
@@ -99,7 +92,7 @@ class PageLocatorTest extends \VuFindTest\Unit\TestCase
                 'pageName' => 'page5',
                 'result' => [
                     'renderer' => 'md',
-                    'path' => $this->fixturePath . '/parent/templates/page-locator-test/page5_aa.md',
+                    'path' => $fixturePath . 'parent/templates/page-locator-test/page5_aa.md',
                     'page' => 'page5_aa',
                 ],
             ],
@@ -107,7 +100,7 @@ class PageLocatorTest extends \VuFindTest\Unit\TestCase
                 'pageName' => 'page6',
                 'result' => [
                     'renderer' => 'md',
-                    'path' => $this->fixturePath . '/parent/templates/page-locator-test/page6_bb.md',
+                    'path' => $fixturePath . 'parent/templates/page-locator-test/page6_bb.md',
                     'page' => 'page6_bb',
                 ],
             ],
@@ -116,20 +109,10 @@ class PageLocatorTest extends \VuFindTest\Unit\TestCase
                 'result' => null,
             ],
         ];
-        $themeInfo = $this->getThemeInfo();
+        $themeInfo = new ThemeInfo(rtrim($fixturePath, '/'), 'parent');
         $pageLocator = new PageLocator($themeInfo, $language, $defaultLanguage);
         foreach ($testCases as $case) {
             $this->assertEquals($case['result'], $pageLocator->determineTemplateAndRenderer($pathPrefix, $case['pageName']));
         }
     }
-
-    /**
-     * Get a test object
-     *
-     * @return ThemeInfo
-     */
-    protected function getThemeInfo()
-    {
-        return new ThemeInfo($this->fixturePath, 'parent');
-    }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/ContentBlock/TemplateBasedTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/ContentBlock/TemplateBasedTest.php
index b9f1b10db81..6fde869b38f 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/ContentBlock/TemplateBasedTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/ContentBlock/TemplateBasedTest.php
@@ -38,6 +38,8 @@ namespace VuFindTest\ContentBlock;
  */
 class TemplateBasedTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test basic functionality of .phtml content block.
      *
@@ -63,7 +65,7 @@ class TemplateBasedTest extends \PHPUnit\Framework\TestCase
      */
     public function testBasicMarkdownFunctionality()
     {
-        $fixturePath = realpath(__DIR__ . '/../../../../../../VuFindTheme/tests/unit-tests/fixtures/themes');
+        $fixturePath = realpath($this->getFixtureDir('VuFindTheme') . 'themes');
         $file = $fixturePath . '/parent/templates/page-locator-test/page4.md';
         $locator = $this->getMockBuilder(\VuFind\Content\PageLocator::class)
             ->disableOriginalConstructor()
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/BrowZineTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/BrowZineTest.php
index acdee46d1f0..aeeb98b282b 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/BrowZineTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/BrowZineTest.php
@@ -41,6 +41,8 @@ use VuFindSearch\Backend\BrowZine\Connector;
  */
 class BrowZineTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Get a mock connector
      *
@@ -68,11 +70,7 @@ class BrowZineTest extends \VuFindTest\Unit\TestCase
      */
     public function testApiSuccess()
     {
-        $fixture = realpath(
-            __DIR__
-            . '/../../../../../tests/fixtures/browzine/doi.json'
-        );
-        $rawData = json_decode(file_get_contents($fixture), true);
+        $rawData = $this->getJsonFixture('browzine/doi.json');
         $testData = [
             [
                 'config' => [],
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/UnpaywallTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/UnpaywallTest.php
index faf7deef3b7..54a1251e033 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/UnpaywallTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/DoiLinker/UnpaywallTest.php
@@ -42,6 +42,8 @@ use VuFind\DoiLinker\Unpaywall;
  */
 class UnpaywallTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test configuration validation.
      *
@@ -65,10 +67,7 @@ class UnpaywallTest extends \VuFindTest\Unit\TestCase
         $adapter = new TestAdapter();
         $testData = [
             [
-                'filename' => realpath(
-                    __DIR__
-                    . '/../../../../../tests/fixtures/unpaywall/goodresponsepdf'
-                ),
+                'fixture' => $this->getFixture('unpaywall/goodresponsepdf'),
                 'response' => [
                     '10.7553/66-4-1434' => [
                         [
@@ -79,10 +78,7 @@ class UnpaywallTest extends \VuFindTest\Unit\TestCase
                 ]
             ],
             [
-                'filename' => realpath(
-                    __DIR__
-                    . '/../../../../../tests/fixtures/unpaywall/goodresponseonline'
-                ),
+                'fixture' => $this->getFixture('unpaywall/goodresponseonline'),
                 'response' => [
                     '10.7553/66-4-1434' => [
                         [
@@ -93,10 +89,7 @@ class UnpaywallTest extends \VuFindTest\Unit\TestCase
                 ]
             ],
             [
-                'filename' => realpath(
-                    __DIR__
-                    . '/../../../../../tests/fixtures/unpaywall/badresponse'
-                ),
+                'fixture' => $this->getFixture('unpaywall/badresponse'),
                 'response' => []
             ],
         ];
@@ -107,8 +100,7 @@ class UnpaywallTest extends \VuFindTest\Unit\TestCase
         $unpaywall = new Unpaywall(new \Laminas\Config\Config($config));
 
         foreach ($testData as $data) {
-            $response = file_get_contents($data['filename']);
-            $responseObj = HttpResponse::fromString($response);
+            $responseObj = HttpResponse::fromString($data['fixture']);
             $adapter->setResponse($responseObj);
             $service = new \VuFindHttp\HttpService();
             $service->setDefaultAdapter($adapter);
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Form/FormTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Form/FormTest.php
index 492317d2980..933b378e6a6 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Form/FormTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Form/FormTest.php
@@ -42,6 +42,8 @@ use VuFind\Form\Form;
  */
 class FormTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test defaults with no configuration.
      *
@@ -219,11 +221,7 @@ class FormTest extends \VuFindTest\Unit\TestCase
      */
     public function testElementOptions()
     {
-        $config = Yaml::parse(
-            file_get_contents(
-                __DIR__ . '/../../../../fixtures/configs/feedbackforms/test.yaml'
-            )
-        );
+        $config = Yaml::parse($this->getFixture('configs/feedbackforms/test.yaml'));
         $mock = $this->getMockBuilder(\VuFind\Config\YamlReader::class)
             ->disableOriginalConstructor()
             ->setMethods(['get'])
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/I18n/Translator/Loader/ExtendedIniTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/I18n/Translator/Loader/ExtendedIniTest.php
index af66f5fccc7..ee730bba71b 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/I18n/Translator/Loader/ExtendedIniTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/I18n/Translator/Loader/ExtendedIniTest.php
@@ -41,6 +41,8 @@ use VuFind\I18n\Translator\Loader\ExtendedIni;
  */
 class ExtendedIniTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test translations.
      *
@@ -49,8 +51,8 @@ class ExtendedIniTest extends \VuFindTest\Unit\TestCase
     public function testTranslations()
     {
         $pathStack = [
-            realpath(__DIR__ . '/../../../../../../fixtures/language/base'),
-            realpath(__DIR__ . '/../../../../../../fixtures/language/overrides')
+            realpath($this->getFixtureDir() . 'language/base'),
+            realpath($this->getFixtureDir() . 'language/overrides')
         ];
         $loader = new ExtendedIni($pathStack);
         $result = $loader->load('en', null);
@@ -73,7 +75,7 @@ class ExtendedIniTest extends \VuFindTest\Unit\TestCase
     public function testFallback()
     {
         $pathStack = [
-            realpath(__DIR__ . '/../../../../../../fixtures/language/base'),
+            realpath($this->getFixtureDir() . 'language/base'),
         ];
         $loader = new ExtendedIni($pathStack, 'en');
         $result = $loader->load('fake', null);
@@ -97,7 +99,7 @@ class ExtendedIniTest extends \VuFindTest\Unit\TestCase
     public function testFallbackToSelf()
     {
         $pathStack = [
-            realpath(__DIR__ . '/../../../../../../fixtures/language/base'),
+            realpath($this->getFixtureDir() . 'language/base'),
         ];
         $loader = new ExtendedIni($pathStack, 'fake');
         $result = $loader->load('fake', null);
@@ -117,7 +119,7 @@ class ExtendedIniTest extends \VuFindTest\Unit\TestCase
     public function testSelfAsParent()
     {
         $pathStack = [
-            realpath(__DIR__ . '/../../../../../../fixtures/language/base'),
+            realpath($this->getFixtureDir() . 'language/base'),
         ];
         $loader = new ExtendedIni($pathStack);
         $result = $loader->load('self-parent', null);
@@ -138,7 +140,7 @@ class ExtendedIniTest extends \VuFindTest\Unit\TestCase
     public function testParentChain()
     {
         $pathStack = [
-            realpath(__DIR__ . '/../../../../../../fixtures/language/base'),
+            realpath($this->getFixtureDir() . 'language/base'),
         ];
         $loader = new ExtendedIni($pathStack);
         $result = $loader->load('child2', null);
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/DAIATest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/DAIATest.php
index 78398a70bbc..f857c283744 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/DAIATest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/DAIATest.php
@@ -46,6 +46,8 @@ use VuFind\ILS\Driver\DAIA;
  */
 class DAIATest extends \VuFindTest\Unit\ILSDriverTestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     protected $testResult = [
         0 =>
             [
@@ -209,17 +211,9 @@ class DAIATest extends \VuFindTest\Unit\ILSDriverTestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $file = realpath(
-                __DIR__ .
-                '/../../../../../../tests/fixtures/daia/response/' . $fixture
+            $responseObj = HttpResponse::fromString(
+                $this->getFixture("daia/response/$fixture")
             );
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(
-                    sprintf('Unable to load fixture file: %s ', $file)
-                );
-            }
-            $response = file_get_contents($file);
-            $responseObj = HttpResponse::fromString($response);
             $adapter->setResponse($responseObj);
         }
         $service = new \VuFindHttp\HttpService();
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/FolioTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/FolioTest.php
index bb911a5283a..d7c44abab7a 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/FolioTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/FolioTest.php
@@ -28,8 +28,6 @@
  */
 namespace VuFindTest\ILS\Driver;
 
-use InvalidArgumentException;
-
 use VuFind\ILS\Driver\Folio;
 
 /**
@@ -43,6 +41,8 @@ use VuFind\ILS\Driver\Folio;
  */
 class FolioTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     protected $testConfig = [
         'API' => [
             'base_url' => 'localhost',
@@ -99,16 +99,7 @@ class FolioTest extends \VuFindTest\Unit\TestCase
     protected function createConnector($test)
     {
         // Setup test responses
-        $file = realpath(
-            __DIR__ .
-            '/../../../../../../tests/fixtures/folio/responses/' . $test . '.json'
-        );
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(
-                sprintf('Unable to load fixture file: %s ', $file)
-            );
-        }
-        $this->testResponses = json_decode(file_get_contents($file), true);
+        $this->testResponses = $this->getJsonFixture("folio/responses/$test.json");
         // Reset log
         $this->testRequestLog = [];
         // Session factory
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/PAIATest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/PAIATest.php
index 486db2cbf06..5049b13505f 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/PAIATest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/PAIATest.php
@@ -46,6 +46,8 @@ use VuFind\ILS\Driver\PAIA;
  */
 class PAIATest extends \VuFindTest\Unit\ILSDriverTestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     protected $validConfig = [
         'DAIA' =>
             [
@@ -562,17 +564,9 @@ class PAIATest extends \VuFindTest\Unit\ILSDriverTestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $file = realpath(
-                __DIR__ .
-                '/../../../../../../tests/fixtures/paia/response/' . $fixture
+            $responseObj = HttpResponse::fromString(
+                $this->getFixture("paia/response/$fixture")
             );
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(
-                    sprintf('Unable to load fixture file: %s ', $file)
-                );
-            }
-            $response = file_get_contents($file);
-            $responseObj = HttpResponse::fromString($response);
             $adapter->setResponse($responseObj);
         }
         $service = new \VuFindHttp\HttpService();
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/XCNCIP2Test.php b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/XCNCIP2Test.php
index 0e74dd84771..21645831fd9 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/XCNCIP2Test.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/ILS/Driver/XCNCIP2Test.php
@@ -43,6 +43,8 @@ use VuFind\ILS\Driver\XCNCIP2;
  */
 class XCNCIP2Test extends \VuFindTest\Unit\ILSDriverTestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Standard setup method.
      *
@@ -1278,17 +1280,9 @@ class XCNCIP2Test extends \VuFindTest\Unit\ILSDriverTestCase
      */
     protected function loadResponse($filename)
     {
-        $file = realpath(
-            __DIR__ .
-            '/../../../../../../tests/fixtures/xcncip2/response/' . $filename
+        return HttpResponse::fromString(
+            $this->getFixture("xcncip2/response/$filename")
         );
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(
-                sprintf('Unable to load fixture file: %s ', $file)
-            );
-        }
-        $response = file_get_contents($file);
-        return HttpResponse::fromString($response);
     }
 
     /**
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/EuropeanaResultsTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/EuropeanaResultsTest.php
index ec925a6867b..2776814e3a0 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/EuropeanaResultsTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/EuropeanaResultsTest.php
@@ -44,6 +44,8 @@ use VuFindTest\Unit\TestCase as TestCase;
  */
 class EuropeanaResultsTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that the module properly parses a sample response.
      *
@@ -110,24 +112,13 @@ class EuropeanaResultsTest extends TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $adapter->setResponse($this->loadResponse($fixture));
+            $adapter->setResponse($this->getFixture("recommend/$fixture"));
         }
         $service = new HttpService();
         $service->setDefaultAdapter($adapter);
         return $service;
     }
 
-    /**
-     * Get a fixture response
-     *
-     * @return string
-     */
-    protected function loadResponse($file)
-    {
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/recommend') . '/';
-        return file_get_contents($fixturePath . $file);
-    }
-
     /**
      * Get a mock results object.
      *
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php
index 42a41ebd5b8..c08abbd2815 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php
@@ -42,6 +42,8 @@ use VuFindTest\Unit\TestCase as TestCase;
  */
 class RandomRecommendTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Standard setup method.
      *
@@ -129,7 +131,7 @@ class RandomRecommendTest extends TestCase
         // Use Solr since some Base components are abstract:
         $params = $this->getServiceManager()
             ->get(\VuFind\Search\Params\PluginManager::class)->get('Solr');
-        $query = $this->getFixture('query');
+        $query = $this->unserializeFixture('query');
         $params->setBasicSearch($query->getString(), $query->getHandler());
         $request = $this->createMock(\Laminas\Stdlib\Parameters::class);
 
@@ -167,7 +169,7 @@ class RandomRecommendTest extends TestCase
         // Use Solr since some Base components are abstract:
         $params = $this->getServiceManager()
             ->get(\VuFind\Search\Params\PluginManager::class)->get('Solr');
-        $query = $this->getFixture('query');
+        $query = $this->unserializeFixture('query');
         $params->setBasicSearch($query->getString(), $query->getHandler());
         $request = $this->createMock(\Laminas\Stdlib\Parameters::class);
 
@@ -195,7 +197,7 @@ class RandomRecommendTest extends TestCase
         $results = $this->getServiceManager()
             ->get(\VuFind\Search\Results\PluginManager::class)->get('Solr');
         $params = $results->getParams();
-        $query = $this->getFixture('query');
+        $query = $this->unserializeFixture('query');
         $params->setBasicSearch($query->getString(), $query->getHandler());
         $request = $this->createMock(\Laminas\Stdlib\Parameters::class);
 
@@ -233,7 +235,7 @@ class RandomRecommendTest extends TestCase
         $results = $this->getServiceManager()
             ->get(\VuFind\Search\Results\PluginManager::class)->get('Solr');
         $params = $results->getParams();
-        $query = $this->getFixture('query');
+        $query = $this->unserializeFixture('query');
         $params->setBasicSearch($query->getString(), $query->getHandler());
         $request = $this->createMock(\Laminas\Stdlib\Parameters::class);
 
@@ -271,9 +273,8 @@ class RandomRecommendTest extends TestCase
      *
      * @return mixed
      */
-    protected function getFixture($file)
+    protected function unserializeFixture($file)
     {
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches/basic') . '/';
-        return unserialize(file_get_contents($fixturePath . $file));
+        return unserialize($this->getFixture("searches/basic/$file"));
     }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/DefaultRecordTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/DefaultRecordTest.php
index f38ffa8366d..1462014a01a 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/DefaultRecordTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/DefaultRecordTest.php
@@ -44,6 +44,8 @@ use VuFind\RecordDriver\Response\PublicationDetails;
  */
 class DefaultRecordTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test getPublicationDates for a record.
      *
@@ -431,15 +433,7 @@ class DefaultRecordTest extends \VuFindTest\Unit\TestCase
      */
     protected function getDriver($overrides = [], Config $mainConfig = null)
     {
-        $fixture = json_decode(
-            file_get_contents(
-                realpath(
-                    VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/misc/testbug2.json'
-                )
-            ),
-            true
-        );
-
+        $fixture = $this->getJsonFixture('misc/testbug2.json');
         $record = new DefaultRecord($mainConfig);
         $record->setRawData($overrides + $fixture['response']['docs'][0]);
         return $record;
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrDefaultTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrDefaultTest.php
index 6c341a8e376..decfa84ce31 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrDefaultTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrDefaultTest.php
@@ -43,6 +43,8 @@ use VuFind\RecordDriver\SolrDefault;
  */
 class SolrDefaultTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test an OpenURL for a book.
      *
@@ -202,15 +204,7 @@ XML;
      */
     protected function getDriver($overrides = [], $searchConfig = [])
     {
-        $fixture = json_decode(
-            file_get_contents(
-                realpath(
-                    VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/misc/testbug2.json'
-                )
-            ),
-            true
-        );
-
+        $fixture = $this->getJsonFixture('misc/testbug2.json');
         $record = new SolrDefault(null, null, new \Laminas\Config\Config($searchConfig));
         $record->setRawData($overrides + $fixture['response']['docs'][0]);
         return $record;
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrMarcTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrMarcTest.php
index d2acb344e36..dfb65debf61 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrMarcTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/RecordDriver/SolrMarcTest.php
@@ -41,6 +41,8 @@ namespace VuFindTest\RecordDriver;
  */
 class SolrMarcTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test a record that used to be known to cause problems because of the way
      * its linking fields are set up.
@@ -56,7 +58,7 @@ class SolrMarcTest extends \VuFindTest\Unit\TestCase
         $configArr = ['Record' => ['marc_links' => '760,765,770,772,774,773,775,777,780,785']];
         $config = new \Laminas\Config\Config($configArr);
         $record = new \VuFind\RecordDriver\SolrMarc($config);
-        $fixture = $this->loadRecordFixture('testbug1.json');
+        $fixture = $this->getJsonFixture('misc/testbug1.json');
         $record->setRawData($fixture['response']['docs'][0]);
         $expected = [
             ['title' => 'A', 'value' => 'Bollettino della Unione matematica italiana', 'link' => ['type' => 'bib', 'value' => '000343528']],
@@ -75,7 +77,7 @@ class SolrMarcTest extends \VuFindTest\Unit\TestCase
     public function testBug2()
     {
         $record = new \VuFind\RecordDriver\SolrMarc();
-        $fixture = $this->loadRecordFixture('testbug2.json');
+        $fixture = $this->getJsonFixture('misc/testbug2.json');
         $record->setRawData($fixture['response']['docs'][0]);
 
         $this->assertEquals(
@@ -102,7 +104,7 @@ class SolrMarcTest extends \VuFindTest\Unit\TestCase
     {
         $config = new \Laminas\Config\Config([]);
         $record = new \VuFind\RecordDriver\SolrMarc($config);
-        $fixture = $this->loadRecordFixture('testbug1.json');
+        $fixture = $this->getJsonFixture('misc/testbug1.json');
         $record->setRawData($fixture['response']['docs'][0]);
         $this->assertEquals(
             [['Matematica', 'Periodici.']],
@@ -129,7 +131,7 @@ class SolrMarcTest extends \VuFindTest\Unit\TestCase
     {
         $config = new \Laminas\Config\Config([]);
         $record = new \VuFind\RecordDriver\SolrMarc($config);
-        $fixture = $this->loadRecordFixture('testbug1.json');
+        $fixture = $this->getJsonFixture('misc/testbug1.json');
         $record->setRawData($fixture['response']['docs'][0]);
         $input = [
             'foo' => 'msg|true',
@@ -158,23 +160,4 @@ class SolrMarcTest extends \VuFindTest\Unit\TestCase
             $record->getFormattedMarcDetails('245', $input)
         );
     }
-
-    /**
-     * Load a fixture file.
-     *
-     * @param string $file File to load from fixture directory.
-     *
-     * @return array
-     */
-    protected function loadRecordFixture($file)
-    {
-        return json_decode(
-            file_get_contents(
-                realpath(
-                    VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/misc/' . $file
-                )
-            ),
-            true
-        );
-    }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Reserves/CsvReaderTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Reserves/CsvReaderTest.php
index 707a0ef5e35..2af4d0cd84b 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Reserves/CsvReaderTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Reserves/CsvReaderTest.php
@@ -40,6 +40,8 @@ use VuFind\Reserves\CsvReader;
  */
 class CsvReaderTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test getInstructors()
      *
@@ -127,7 +129,7 @@ class CsvReaderTest extends \VuFindTest\Unit\TestCase
     {
         $reader = $this->getReader();
         $reader->getReserves();
-        $fixture = $this->getFixturePath('reserves.csv');
+        $fixture = $this->getFixtureDir() . "reserves/reserves.csv";
         $errors = "Skipping empty/missing Bib ID: $fixture, line 3\nSkipping incomplete row: $fixture, line 5\n";
         $this->assertEquals($errors, $reader->getErrors());
     }
@@ -154,18 +156,6 @@ class CsvReaderTest extends \VuFindTest\Unit\TestCase
      */
     protected function getReader($fixture = 'reserves.csv')
     {
-        return new CsvReader($this->getFixturePath($fixture));
-    }
-
-    /**
-     * Get a fixture path
-     *
-     * @param string $fixture Name of file to load
-     *
-     * @return string
-     */
-    protected function getFixturePath($fixture)
-    {
-        return realpath(__DIR__ . '/../../../../fixtures/reserves/' . $fixture);
+        return new CsvReader($this->getFixtureDir() . "reserves/$fixture");
     }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/AlmaTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/AlmaTest.php
index 636ac0f0c18..53b11a3c5e6 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/AlmaTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/AlmaTest.php
@@ -50,6 +50,8 @@ use VuFind\Resolver\Driver\Alma;
  */
 class AlmaTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test-Config
      *
@@ -172,17 +174,9 @@ class AlmaTest extends \VuFindTest\Unit\TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $file = realpath(
-                __DIR__ .
-                '/../../../../../../tests/fixtures/resolver/response/' . $fixture
+            $responseObj = HttpResponse::fromString(
+                $this->getFixture("resolver/response/$fixture")
             );
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(
-                    sprintf('Unable to load fixture file: %s ', $file)
-                );
-            }
-            $response = file_get_contents($file);
-            $responseObj = HttpResponse::fromString($response);
             $adapter->setResponse($responseObj);
         }
         $_SERVER['REMOTE_ADDR'] = "127.0.0.1";
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/EzbTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/EzbTest.php
index 5bcccd54feb..b3b114185a4 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/EzbTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/EzbTest.php
@@ -47,6 +47,8 @@ use VuFind\Resolver\Driver\Ezb;
  */
 class EzbTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test-Config
      *
@@ -163,17 +165,9 @@ class EzbTest extends \VuFindTest\Unit\TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $file = realpath(
-                __DIR__ .
-                '/../../../../../../tests/fixtures/resolver/response/' . $fixture
+            $responseObj = HttpResponse::fromString(
+                $this->getFixture("resolver/response/$fixture")
             );
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(
-                    sprintf('Unable to load fixture file: %s ', $file)
-                );
-            }
-            $response = file_get_contents($file);
-            $responseObj = HttpResponse::fromString($response);
             $adapter->setResponse($responseObj);
         }
         $client = new \Laminas\Http\Client();
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/RediTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/RediTest.php
index 820c9a28ac5..01cec8fff44 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/RediTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Resolver/Driver/RediTest.php
@@ -47,6 +47,8 @@ use VuFind\Resolver\Driver\Redi;
  */
 class RediTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test-Config
      *
@@ -117,17 +119,9 @@ class RediTest extends \VuFindTest\Unit\TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $file = realpath(
-                __DIR__ .
-                '/../../../../../../tests/fixtures/resolver/response/' . $fixture
+            $responseObj = HttpResponse::fromString(
+                $this->getFixture("resolver/response/$fixture")
             );
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(
-                    sprintf('Unable to load fixture file: %s ', $file)
-                );
-            }
-            $response = file_get_contents($file);
-            $responseObj = HttpResponse::fromString($response);
             $adapter->setResponse($responseObj);
         }
         $client = new \Laminas\Http\Client();
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php
index 8d9cc083fa7..9e3c1313c52 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php
@@ -43,6 +43,8 @@ use VuFindTest\Unit\TestCase as TestCase;
  */
 class QueryAdapterTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test various conversions.
      *
@@ -51,11 +53,10 @@ class QueryAdapterTest extends TestCase
     public function testConversions()
     {
         $cases = ['basic', 'advanced'];
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches') . '/';
         foreach ($cases as $case) {
             // Load minified, unminified, and Query object data:
-            $min = unserialize(file_get_contents($fixturePath . $case . '/min'));
-            $q = unserialize(file_get_contents($fixturePath . $case . '/query'));
+            $min = unserialize($this->getFixture('searches/' . $case . '/min'));
+            $q = unserialize($this->getFixture('searches/' . $case . '/query'));
 
             // Test conversion of minified data:
             $this->assertEquals($q, QueryAdapter::deminify($min));
@@ -75,8 +76,7 @@ class QueryAdapterTest extends TestCase
      */
     public function testOperatorDefinedEverywhere()
     {
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches') . '/';
-        $q = unserialize(file_get_contents($fixturePath . '/operators'));
+        $q = unserialize($this->getFixture('searches/operators'));
         $minified = QueryAdapter::minify($q);
 
         // First, check that count of 'o' values matches count of queries in group:
@@ -102,9 +102,8 @@ class QueryAdapterTest extends TestCase
      */
     public function testAdvancedRequest()
     {
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches') . '/advanced/';
-        $req = unserialize(file_get_contents($fixturePath . 'request'));
-        $q = unserialize(file_get_contents($fixturePath . 'query'));
+        $req = unserialize($this->getFixture('searches/advanced/request'));
+        $q = unserialize($this->getFixture('searches/advanced/query'));
         $this->assertEquals($q, QueryAdapter::fromRequest($req, 'AllFields'));
     }
 
@@ -138,9 +137,8 @@ class QueryAdapterTest extends TestCase
         };
 
         // Run the tests:
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches') . '/';
         foreach ($cases as $case => $expected) {
-            $q = unserialize(file_get_contents($fixturePath . $case . '/query'));
+            $q = unserialize($this->getFixture('searches/' . $case . '/query'));
             $this->assertEquals($expected, QueryAdapter::display($q, $echo, $echo));
         }
     }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/SpellingProcessorTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/SpellingProcessorTest.php
index 091efc63312..0cf5390c688 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/SpellingProcessorTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/SpellingProcessorTest.php
@@ -43,6 +43,8 @@ use VuFindTest\Unit\TestCase;
  */
 class SpellingProcessorTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test defaults.
      *
@@ -76,8 +78,8 @@ class SpellingProcessorTest extends TestCase
     public function testSuggestionProcessing()
     {
         $sp = new SpellingProcessor();
-        $spelling = $this->getFixture('spell1');
-        $query = $this->getFixture('query1');
+        $spelling = $this->unserializeFixture('spell1');
+        $query = $this->unserializeFixture('query1');
         $this->assertEquals(
             $this->getExpectedQuery1Suggestions(),
             $sp->getSuggestions($spelling, $query)
@@ -93,8 +95,8 @@ class SpellingProcessorTest extends TestCase
     {
         $config = new Config(['limit' => 5]);
         $sp = new SpellingProcessor($config);
-        $spelling = $this->getFixture('spell1');
-        $query = $this->getFixture('query1');
+        $spelling = $this->unserializeFixture('spell1');
+        $query = $this->unserializeFixture('query1');
         $this->assertEquals(
             [
                 'grumble' => [
@@ -128,8 +130,8 @@ class SpellingProcessorTest extends TestCase
      */
     public function testBasicSuggestions()
     {
-        $spelling = $this->getFixture('spell1');
-        $query = $this->getFixture('query1');
+        $spelling = $this->unserializeFixture('spell1');
+        $query = $this->unserializeFixture('query1');
         $params = $this->getServiceManager()
             ->get(\VuFind\Search\Params\PluginManager::class)->get('Solr');
         $params->setBasicSearch($query->getString(), $query->getHandler());
@@ -190,8 +192,8 @@ class SpellingProcessorTest extends TestCase
      */
     public function testBasicSuggestionsForUppercaseQuery()
     {
-        $spelling = $this->getFixture('spell6');
-        $query = $this->getFixture('query6');
+        $spelling = $this->unserializeFixture('spell6');
+        $query = $this->unserializeFixture('query6');
         $params = $this->getServiceManager()
             ->get(\VuFind\Search\Params\PluginManager::class)->get('Solr');
         $params->setBasicSearch($query->getString(), $query->getHandler());
@@ -252,8 +254,8 @@ class SpellingProcessorTest extends TestCase
      */
     public function testBasicSuggestionsWithNonDefaultSettings()
     {
-        $spelling = $this->getFixture('spell1');
-        $query = $this->getFixture('query1');
+        $spelling = $this->unserializeFixture('spell1');
+        $query = $this->unserializeFixture('query1');
         $params = $this->getServiceManager()
             ->get(\VuFind\Search\Params\PluginManager::class)->get('Solr');
         $params->setBasicSearch($query->getString(), $query->getHandler());
@@ -472,8 +474,8 @@ class SpellingProcessorTest extends TestCase
         $this->expectExceptionMessage('Unexpected suggestion format; spellcheck.extendedResults must be set to true.');
 
         $sp = new SpellingProcessor(new Config([]));
-        $spelling = $this->getFixture('spell5');
-        $query = $this->getFixture('query5');
+        $spelling = $this->unserializeFixture('spell5');
+        $query = $this->unserializeFixture('query5');
         $sp->getSuggestions($spelling, $query);
     }
 
@@ -488,8 +490,8 @@ class SpellingProcessorTest extends TestCase
      */
     protected function runSpellingTest($testNum, $expected, $config = [])
     {
-        $spelling = $this->getFixture('spell' . $testNum);
-        $query = $this->getFixture('query' . $testNum);
+        $spelling = $this->unserializeFixture('spell' . $testNum);
+        $query = $this->unserializeFixture('query' . $testNum);
         $params = $this->getServiceManager()
             ->get(\VuFind\Search\Params\PluginManager::class)->get('Solr');
         $this->setProperty($params, 'query', $query);
@@ -562,9 +564,8 @@ class SpellingProcessorTest extends TestCase
      *
      * @return mixed
      */
-    protected function getFixture($file)
+    protected function unserializeFixture($file)
     {
-        $fixturePath = realpath(__DIR__ . '/../../../../../fixtures/spell') . '/';
-        return unserialize(file_get_contents($fixturePath . $file));
+        return unserialize($this->getFixture("spell/$file"));
     }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V3/ErrorListenerTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V3/ErrorListenerTest.php
index 29350c546c1..2832342e796 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V3/ErrorListenerTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V3/ErrorListenerTest.php
@@ -33,7 +33,6 @@ use Laminas\EventManager\Event;
 use Laminas\Http\Response;
 
 use PHPUnit\Framework\TestCase;
-use RuntimeException;
 
 use VuFind\Search\Solr\V3\ErrorListener;
 
@@ -50,6 +49,8 @@ use VuFindSearch\Backend\Exception\HttpErrorException;
  */
 class ErrorListenerTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Detect parser error response.
      *
@@ -97,15 +98,8 @@ class ErrorListenerTest extends TestCase
      */
     protected function createResponse($name)
     {
-        $file = realpath(
-            \VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/response/solr/' . $name
+        return Response::fromString(
+            $this->getFixture('response/solr/' . $name)
         );
-        if (!$file) {
-            throw new RuntimeException(
-                sprintf('Unable to resolve fixture to fixture file: %s', $name)
-            );
-        }
-        $response = Response::fromString(file_get_contents($file));
-        return $response;
     }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V4/ErrorListenerTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V4/ErrorListenerTest.php
index e4ce4aed287..84496917c80 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V4/ErrorListenerTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/Solr/V4/ErrorListenerTest.php
@@ -33,7 +33,6 @@ use Laminas\EventManager\Event;
 use Laminas\Http\Response;
 
 use PHPUnit\Framework\TestCase;
-use RuntimeException;
 
 use VuFind\Search\Solr\V4\ErrorListener;
 
@@ -50,6 +49,8 @@ use VuFindSearch\Backend\Exception\HttpErrorException;
  */
 class ErrorListenerTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Detect parser error response.
      *
@@ -97,15 +98,8 @@ class ErrorListenerTest extends TestCase
      */
     protected function createResponse($name)
     {
-        $file = realpath(
-            \VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/response/solr/' . $name
+        return Response::fromString(
+            $this->getFixture('response/solr/' . $name)
         );
-        if (!$file) {
-            throw new RuntimeException(
-                sprintf('Unable to resolve fixture to fixture file: %s', $name)
-            );
-        }
-        $response = Response::fromString(file_get_contents($file));
-        return $response;
     }
 }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/UrlQueryHelperTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/UrlQueryHelperTest.php
index b3f59b0fa3e..cc8a95a7c73 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/UrlQueryHelperTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/UrlQueryHelperTest.php
@@ -44,6 +44,8 @@ use VuFindTest\Unit\TestCase as TestCase;
  */
 class UrlQueryHelperTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Get a preconfigured helper.
      *
@@ -195,8 +197,7 @@ class UrlQueryHelperTest extends TestCase
      */
     public function testAdvancedSearch()
     {
-        $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches') . '/advanced/';
-        $q = unserialize(file_get_contents($fixturePath . 'query'));
+        $q = unserialize($this->getFixture('searches/advanced/query'));
         $helper = new UrlQueryHelper([], $q);
         $this->assertEquals(
             '?join=OR&bool0%5B%5D=AND&lookfor0%5B%5D=oranges&lookfor0%5B%5D=bananas'
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/OpenUrlTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/OpenUrlTest.php
index ebc256be7fe..f818ea86650 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/OpenUrlTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/OpenUrlTest.php
@@ -43,6 +43,8 @@ use VuFind\View\Helper\Root\OpenUrl;
  */
 class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Configuration array providing basic settings for testing OpenUrlRules
      *
@@ -112,7 +114,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
     public function testCheckExcludedRecordsRulesFalse()
     {
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule1.json"), $this->rulesConfig)
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule1.json"), $this->rulesConfig)
             ->__invoke($this->getMockDriver(), 'results');
         $this->assertTrue($openUrl->isActive());
     }
@@ -126,7 +128,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
     public function testCheckExcludedRecordsRulesTrue()
     {
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule2.json"), $this->rulesConfig)
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule2.json"), $this->rulesConfig)
             ->__invoke($this->getMockDriver(), 'results');
         $this->assertFalse($openUrl->isActive());
     }
@@ -144,7 +146,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
             'fake-data', 'VuFind\RecordDriver\SolrMarc', ['Article'], false
         );
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule5.json"), $this->rulesConfig)
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule5.json"), $this->rulesConfig)
             ->__invoke($driver, 'results');
         $this->assertFalse($openUrl->isActive());
     }
@@ -158,7 +160,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
     public function testCheckSupportedRecordsRulesFalse()
     {
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule3.json"), $this->rulesConfig)
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule3.json"), $this->rulesConfig)
             ->__invoke($this->getMockDriver(), 'results');
         $this->assertFalse($openUrl->isActive());
     }
@@ -176,7 +178,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
             'fake-openurl', 'VuFind\RecordDriver\SolrDefault', ['CrazyFormat']
         );
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule5.json"), $this->rulesConfig)
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule5.json"), $this->rulesConfig)
             ->__invoke($driver, 'results');
         $this->assertFalse($openUrl->isActive());
     }
@@ -190,7 +192,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
     public function testCheckSupportedRecordsRulesTrue()
     {
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule4.json"), $this->rulesConfig)
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule4.json"), $this->rulesConfig)
             ->__invoke($this->getMockDriver(), 'results');
         $this->assertTrue($openUrl->isActive());
     }
@@ -211,7 +213,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
             'fake-data', 'VuFind\RecordDriver\SolrMarc', $formats
         );
         $openUrl = $this
-            ->getOpenUrl($this->getFixture("rule1.json"), $this->rulesConfig);
+            ->getOpenUrl($this->getJsonFixture("openurlrules/rule1.json"), $this->rulesConfig);
         $this->assertTrue($openUrl->__invoke($defaultDriver, 'results')->isActive());
         $this->assertFalse($openUrl->__invoke($marcDriver, 'results')->isActive());
     }
@@ -253,31 +255,6 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
         return $driver;
     }
 
-    /**
-     * Get the fixtures for testing OpenUrlRules
-     *
-     * @param string $fixture filename of the fixture to load
-     *
-     * @return mixed|null
-     */
-    protected function getFixture($fixture)
-    {
-        if ($fixture) {
-            $file = realpath(
-                __DIR__ .
-                '/../../../../../../../tests/fixtures/openurlrules/' . $fixture
-            );
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new \InvalidArgumentException(
-                    sprintf('Unable to load fixture file: %s ', $fixture)
-                );
-            }
-            return json_decode(file_get_contents($file), true);
-        }
-
-        return null;
-    }
-
     /**
      * Get the object to test
      *
@@ -290,7 +267,7 @@ class OpenUrlTest extends \VuFindTest\Unit\ViewHelperTestCase
     protected function getOpenUrl($rules = null, $config = [], $mockContext = null)
     {
         if (null === $rules) {
-            $rules = $this->getFixture('defaults.json');
+            $rules = $this->getJsonFixture('openurlrules/defaults.json');
         }
         if (null === $mockContext) {
             $mockContext = $this->getMockContext();
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php
index 275dccaccff..2ef69a00557 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php
@@ -41,6 +41,8 @@ use VuFind\View\Helper\Root\RecordDataFormatterFactory;
  */
 class RecordDataFormatterTest extends \VuFindTest\Unit\ViewHelperTestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Get a mock record router.
      *
@@ -119,14 +121,7 @@ class RecordDataFormatterTest extends \VuFindTest\Unit\ViewHelperTestCase
             ->will($this->returnValue($authors));
 
         // Load record data from fixture file:
-        $fixture = json_decode(
-            file_get_contents(
-                realpath(
-                    VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/misc/testbug2.json'
-                )
-            ),
-            true
-        );
+        $fixture = $this->getJsonFixture('misc/testbug2.json');
         $record->setRawData($overrides + $fixture['response']['docs'][0]);
         return $record;
     }
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php
index ab44fbde884..a3c8f9452f1 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php
@@ -44,6 +44,8 @@ use VuFindTheme\ThemeInfo;
  */
 class RecordTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Theme to use for testing purposes.
      *
@@ -616,14 +618,7 @@ class RecordTest extends \PHPUnit\Framework\TestCase
      */
     protected function loadRecordFixture($file)
     {
-        $json = json_decode(
-            file_get_contents(
-                realpath(
-                    VUFIND_PHPUNIT_MODULE_PATH . '/fixtures/misc/' . $file
-                )
-            ),
-            true
-        );
+        $json = $this->getJsonFixture('misc/' . $file);
         $record = new \VuFind\RecordDriver\SolrMarc();
         $record->setRawData($json['response']['docs'][0]);
         return $record;
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/DynamicRouteCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/DynamicRouteCommandTest.php
index 3ebd1bb36d0..b75a9935bf6 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/DynamicRouteCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/DynamicRouteCommandTest.php
@@ -44,6 +44,8 @@ use VuFindConsole\Generator\GeneratorTools;
  */
 class DynamicRouteCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that missing parameters yield an error message.
      *
@@ -73,7 +75,7 @@ class DynamicRouteCommandTest extends \PHPUnit\Framework\TestCase
      */
     public function testSuccessWithMinimalParameters()
     {
-        $configFixturePath = __DIR__ . '/../../../../../fixtures/empty.config.php';
+        $configFixturePath = $this->getFixtureDir('VuFindConsole') . 'empty.config.php';
         $expectedConfig = include $configFixturePath;
         $tools = $this->getMockGeneratorTools(
             ['getModuleConfigPath', 'backUpFile', 'writeModuleConfig']
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/NonTabRecordActionCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/NonTabRecordActionCommandTest.php
index 8ff33dd71fa..4befb3e8b4b 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/NonTabRecordActionCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/NonTabRecordActionCommandTest.php
@@ -42,6 +42,8 @@ use VuFindConsole\Generator\GeneratorTools;
  */
 class NonTabRecordActionCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that missing parameters yield an error message.
      *
@@ -71,7 +73,7 @@ class NonTabRecordActionCommandTest extends \PHPUnit\Framework\TestCase
      */
     public function testSuccessWithMinimalParameters()
     {
-        $configFixturePath = __DIR__ . '/../../../../../fixtures/empty.config.php';
+        $configFixturePath = $this->getFixtureDir('VuFindConsole') . 'empty.config.php';
         $expectedConfig = [
             'router' => [
                 'routes' => [
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/RecordRouteCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/RecordRouteCommandTest.php
index e58e1fb7cc0..20955bd9619 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/RecordRouteCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/RecordRouteCommandTest.php
@@ -44,6 +44,8 @@ use VuFindConsole\Generator\GeneratorTools;
  */
 class RecordRouteCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that missing parameters yield an error message.
      *
@@ -73,7 +75,7 @@ class RecordRouteCommandTest extends \PHPUnit\Framework\TestCase
      */
     public function testSuccessWithMinimalParameters()
     {
-        $configFixturePath = __DIR__ . '/../../../../../fixtures/empty.config.php';
+        $configFixturePath = $this->getFixtureDir('VuFindConsole') . 'empty.config.php';
         $expectedConfig = include $configFixturePath;
         $tools = $this->getMockGeneratorTools(
             ['getModuleConfigPath', 'backUpFile', 'writeModuleConfig']
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/StaticRouteCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/StaticRouteCommandTest.php
index e8fa0dfd0de..c91eb79860f 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/StaticRouteCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Generate/StaticRouteCommandTest.php
@@ -44,6 +44,8 @@ use VuFindConsole\Generator\GeneratorTools;
  */
 class StaticRouteCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that missing parameters yield an error message.
      *
@@ -73,7 +75,7 @@ class StaticRouteCommandTest extends \PHPUnit\Framework\TestCase
      */
     public function testSuccessWithMinimalParameters()
     {
-        $configFixturePath = __DIR__ . '/../../../../../fixtures/empty.config.php';
+        $configFixturePath = $this->getFixtureDir('VuFindConsole') . 'empty.config.php';
         $expectedConfig = include $configFixturePath;
         $tools = $this->getMockGeneratorTools(
             ['getModuleConfigPath', 'backUpFile', 'writeModuleConfig']
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Harvest/MergeMarcCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Harvest/MergeMarcCommandTest.php
index 284892bedc4..444f6b582f8 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Harvest/MergeMarcCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Harvest/MergeMarcCommandTest.php
@@ -41,6 +41,8 @@ use VuFindConsole\Command\Harvest\MergeMarcCommand;
  */
 class MergeMarcCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that missing parameters yield an error message.
      *
@@ -68,7 +70,7 @@ class MergeMarcCommandTest extends \PHPUnit\Framework\TestCase
     {
         $command = new MergeMarcCommand();
         $commandTester = new CommandTester($command);
-        $directory = __DIR__ . '/../../../../../fixtures/xml';
+        $directory = $this->getFixtureDir('VuFindConsole') . 'xml';
         $commandTester->execute(compact('directory'));
         $expected = <<<EXPECTED
 <collection>
@@ -92,7 +94,7 @@ EXPECTED;
     {
         $command = new MergeMarcCommand();
         $commandTester = new CommandTester($command);
-        $directory = __DIR__ . '/../../../../../fixtures/does-not-exist';
+        $directory = $this->getFixtureDir('VuFindConsole') . 'does-not-exist';
         $commandTester->execute(compact('directory'));
         $expected = "Cannot open directory: $directory\n";
         $this->assertEquals($expected, $commandTester->getDisplay());
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Import/WebCrawlCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Import/WebCrawlCommandTest.php
index 165cf6a7010..65bcfb541a5 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Import/WebCrawlCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Import/WebCrawlCommandTest.php
@@ -44,6 +44,8 @@ use VuFindConsole\Command\Import\WebCrawlCommand;
  */
 class WebCrawlCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test the simplest possible success case.
      *
@@ -51,8 +53,8 @@ class WebCrawlCommandTest extends \PHPUnit\Framework\TestCase
      */
     public function testSuccessWithMinimalParameters()
     {
-        $fixture1 = __DIR__ . '/../../../../../fixtures/sitemap/index.xml';
-        $fixture2 = __DIR__ . '/../../../../../fixtures/sitemap/map.xml';
+        $fixture1 = $this->getFixtureDir('VuFindConsole') . 'sitemap/index.xml';
+        $fixture2 = $this->getFixtureDir('VuFindConsole') . 'sitemap/map.xml';
         $importer = $this->getMockImporter();
         $importer->expects($this->once())->method('save')
             ->with(
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/AddUsingTemplateCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/AddUsingTemplateCommandTest.php
index 5a6edb549d4..3f643f32c58 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/AddUsingTemplateCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/AddUsingTemplateCommandTest.php
@@ -43,12 +43,24 @@ use VuFindConsole\Command\Language\AddUsingTemplateCommand;
  */
 class AddUsingTemplateCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Language fixture directory
      *
      * @var string
      */
-    protected $languageFixtureDir = __DIR__ . '/../../../../../fixtures/language';
+    protected $languageFixtureDir = null;
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp(): void
+    {
+        $this->languageFixtureDir = $this->getFixtureDir('VuFindConsole') . 'language';
+    }
 
     /**
      * Test that missing parameters yield an error message.
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/CopyStringCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/CopyStringCommandTest.php
index c7fab3cace6..efd57af1e2c 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/CopyStringCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/CopyStringCommandTest.php
@@ -43,12 +43,24 @@ use VuFindConsole\Command\Language\CopyStringCommand;
  */
 class CopyStringCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Language fixture directory
      *
      * @var string
      */
-    protected $languageFixtureDir = __DIR__ . '/../../../../../fixtures/language';
+    protected $languageFixtureDir = null;
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp(): void
+    {
+        $this->languageFixtureDir = $this->getFixtureDir('VuFindConsole') . 'language';
+    }
 
     /**
      * Test that missing parameters yield an error message.
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/DeleteCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/DeleteCommandTest.php
index 1a560dc93df..e83ca5ae86d 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/DeleteCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/DeleteCommandTest.php
@@ -43,12 +43,24 @@ use VuFindConsole\Command\Language\DeleteCommand;
  */
 class DeleteCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Language fixture directory
      *
      * @var string
      */
-    protected $languageFixtureDir = __DIR__ . '/../../../../../fixtures/language';
+    protected $languageFixtureDir = null;
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp(): void
+    {
+        $this->languageFixtureDir = $this->getFixtureDir('VuFindConsole') . 'language';
+    }
 
     /**
      * Test that missing parameters yield an error message.
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/NormalizeCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/NormalizeCommandTest.php
index c7350f0082b..6fa985d0228 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/NormalizeCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Language/NormalizeCommandTest.php
@@ -43,12 +43,24 @@ use VuFindConsole\Command\Language\NormalizeCommand;
  */
 class NormalizeCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Language fixture directory
      *
      * @var string
      */
-    protected $languageFixtureDir = __DIR__ . '/../../../../../fixtures/language';
+    protected $languageFixtureDir = null;
+
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setUp(): void
+    {
+        $this->languageFixtureDir = $this->getFixtureDir('VuFindConsole') . 'language';
+    }
 
     /**
      * Test that missing parameters yield an error message.
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DedupeCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DedupeCommandTest.php
index f5f6aa4c0c7..906a6b7d2d8 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DedupeCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DedupeCommandTest.php
@@ -43,6 +43,8 @@ use VuFindConsole\Command\Util\DedupeCommand;
  */
 class DedupeCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Get a mocked-out command object.
      *
@@ -114,7 +116,7 @@ class DedupeCommandTest extends \PHPUnit\Framework\TestCase
         $command = $this->getMockCommand();
         $this->setSuccessfulExpectations($command, $outputFilename);
         $commandTester = new CommandTester($command);
-        $fixture = __DIR__ . '/../../../../../fixtures/fileWithDuplicateLines';
+        $fixture = $this->getFixtureDir('VuFindConsole') . 'fileWithDuplicateLines';
         $commandTester->execute(
             [
                 'input' => $fixture,
@@ -132,7 +134,7 @@ class DedupeCommandTest extends \PHPUnit\Framework\TestCase
      */
     public function testSuccessWithoutArguments()
     {
-        $fixture = __DIR__ . '/../../../../../fixtures/fileWithDuplicateLines';
+        $fixture = $this->getFixtureDir('VuFindConsole') . 'fileWithDuplicateLines';
         $outputFilename = '/fake/outfile';
         $command = $this->getMockCommand();
         $command->expects($this->at(0))->method('getInput')
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DeletesCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DeletesCommandTest.php
index 6044aec354b..a65b5da74c2 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DeletesCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/DeletesCommandTest.php
@@ -41,6 +41,8 @@ use VuFindConsole\Command\Util\DeletesCommand;
  */
 class DeletesCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Get mock Solr writer.
      *
@@ -101,7 +103,7 @@ class DeletesCommandTest extends \PHPUnit\Framework\TestCase
             ->with($this->equalTo('Solr'), $this->equalTo(['rec1', 'rec2', 'rec3']));
         $command = new DeletesCommand($writer);
         $commandTester = new CommandTester($command);
-        $fixture = __DIR__ . '/../../../../../fixtures/deletes';
+        $fixture = $this->getFixtureDir('VuFindConsole') . 'deletes';
         $commandTester->execute(
             [
                 'filename' => $fixture,
diff --git a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/IndexReservesCommandTest.php b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/IndexReservesCommandTest.php
index 26bcff0c308..34c8f5fb94e 100644
--- a/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/IndexReservesCommandTest.php
+++ b/module/VuFindConsole/tests/unit-tests/src/VuFindTest/Command/Util/IndexReservesCommandTest.php
@@ -43,6 +43,8 @@ use VuFindConsole\Command\Util\IndexReservesCommand;
  */
 class IndexReservesCommandTest extends \PHPUnit\Framework\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Get mock ILS connection.
      *
@@ -176,8 +178,8 @@ class IndexReservesCommandTest extends \PHPUnit\Framework\TestCase
             ->with($this->equalTo('SolrReserves'));
         $command = $this->getCommand($writer);
         $commandTester = new CommandTester($command);
-        $fixture1 = __DIR__ . '/../../../../../fixtures/reserves/fixture1';
-        $fixture2 = __DIR__ . '/../../../../../fixtures/reserves/fixture2';
+        $fixture1 = $this->getFixtureDir('VuFindConsole') . 'reserves/fixture1';
+        $fixture2 = $this->getFixtureDir('VuFindConsole') . 'reserves/fixture2';
         $commandTester->execute(
             [
                 '--filename' => [$fixture1, $fixture2],
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/browzine/response/search b/module/VuFindSearch/tests/fixtures/browzine/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/browzine/response/search
rename to module/VuFindSearch/tests/fixtures/browzine/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eds/query/advanced b/module/VuFindSearch/tests/fixtures/eds/query/advanced
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eds/query/advanced
rename to module/VuFindSearch/tests/fixtures/eds/query/advanced
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eds/response/autocomplete b/module/VuFindSearch/tests/fixtures/eds/response/autocomplete
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eds/response/autocomplete
rename to module/VuFindSearch/tests/fixtures/eds/response/autocomplete
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eds/response/retrieve b/module/VuFindSearch/tests/fixtures/eds/response/retrieve
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eds/response/retrieve
rename to module/VuFindSearch/tests/fixtures/eds/response/retrieve
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eds/response/search b/module/VuFindSearch/tests/fixtures/eds/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eds/response/search
rename to module/VuFindSearch/tests/fixtures/eds/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eit/query/advanced b/module/VuFindSearch/tests/fixtures/eit/query/advanced
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eit/query/advanced
rename to module/VuFindSearch/tests/fixtures/eit/query/advanced
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eit/response/retrieve b/module/VuFindSearch/tests/fixtures/eit/response/retrieve
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eit/response/retrieve
rename to module/VuFindSearch/tests/fixtures/eit/response/retrieve
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/eit/response/search b/module/VuFindSearch/tests/fixtures/eit/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/eit/response/search
rename to module/VuFindSearch/tests/fixtures/eit/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/libguides/response/search b/module/VuFindSearch/tests/fixtures/libguides/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/libguides/response/search
rename to module/VuFindSearch/tests/fixtures/libguides/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/pazpar2/response/pp2search b/module/VuFindSearch/tests/fixtures/pazpar2/response/pp2search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/pazpar2/response/pp2search
rename to module/VuFindSearch/tests/fixtures/pazpar2/response/pp2search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/pazpar2/response/pp2show b/module/VuFindSearch/tests/fixtures/pazpar2/response/pp2show
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/pazpar2/response/pp2show
rename to module/VuFindSearch/tests/fixtures/pazpar2/response/pp2show
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/primo/response/error-with-success-http b/module/VuFindSearch/tests/fixtures/primo/response/error-with-success-http
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/primo/response/error-with-success-http
rename to module/VuFindSearch/tests/fixtures/primo/response/error-with-success-http
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/primo/response/record-http b/module/VuFindSearch/tests/fixtures/primo/response/record-http
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/primo/response/record-http
rename to module/VuFindSearch/tests/fixtures/primo/response/record-http
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/primo/response/retrieve b/module/VuFindSearch/tests/fixtures/primo/response/retrieve
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/primo/response/retrieve
rename to module/VuFindSearch/tests/fixtures/primo/response/retrieve
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/primo/response/search b/module/VuFindSearch/tests/fixtures/primo/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/primo/response/search
rename to module/VuFindSearch/tests/fixtures/primo/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/primo/response/search-http b/module/VuFindSearch/tests/fixtures/primo/response/search-http
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/primo/response/search-http
rename to module/VuFindSearch/tests/fixtures/primo/response/search-http
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/primo/response/swansea-search-http b/module/VuFindSearch/tests/fixtures/primo/response/swansea-search-http
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/primo/response/swansea-search-http
rename to module/VuFindSearch/tests/fixtures/primo/response/swansea-search-http
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/searchspecs.yaml b/module/VuFindSearch/tests/fixtures/searchspecs.yaml
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/searchspecs.yaml
rename to module/VuFindSearch/tests/fixtures/searchspecs.yaml
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/bad-request b/module/VuFindSearch/tests/fixtures/solr/response/bad-request
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/bad-request
rename to module/VuFindSearch/tests/fixtures/solr/response/bad-request
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/internal-server-error b/module/VuFindSearch/tests/fixtures/solr/response/internal-server-error
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/internal-server-error
rename to module/VuFindSearch/tests/fixtures/solr/response/internal-server-error
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/morelikethis b/module/VuFindSearch/tests/fixtures/solr/response/morelikethis
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/morelikethis
rename to module/VuFindSearch/tests/fixtures/solr/response/morelikethis
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record b/module/VuFindSearch/tests/fixtures/solr/response/multi-record
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record
rename to module/VuFindSearch/tests/fixtures/solr/response/multi-record
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record-part1 b/module/VuFindSearch/tests/fixtures/solr/response/multi-record-part1
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record-part1
rename to module/VuFindSearch/tests/fixtures/solr/response/multi-record-part1
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record-part2 b/module/VuFindSearch/tests/fixtures/solr/response/multi-record-part2
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record-part2
rename to module/VuFindSearch/tests/fixtures/solr/response/multi-record-part2
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record-part3 b/module/VuFindSearch/tests/fixtures/solr/response/multi-record-part3
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/multi-record-part3
rename to module/VuFindSearch/tests/fixtures/solr/response/multi-record-part3
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/no-match b/module/VuFindSearch/tests/fixtures/solr/response/no-match
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/no-match
rename to module/VuFindSearch/tests/fixtures/solr/response/no-match
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/single-record b/module/VuFindSearch/tests/fixtures/solr/response/single-record
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/single-record
rename to module/VuFindSearch/tests/fixtures/solr/response/single-record
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/solr/response/terms b/module/VuFindSearch/tests/fixtures/solr/response/terms
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/solr/response/terms
rename to module/VuFindSearch/tests/fixtures/solr/response/terms
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/summon/query/advanced b/module/VuFindSearch/tests/fixtures/summon/query/advanced
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/summon/query/advanced
rename to module/VuFindSearch/tests/fixtures/summon/query/advanced
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/summon/query/basic b/module/VuFindSearch/tests/fixtures/summon/query/basic
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/summon/query/basic
rename to module/VuFindSearch/tests/fixtures/summon/query/basic
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/summon/response/retrieve1 b/module/VuFindSearch/tests/fixtures/summon/response/retrieve1
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/summon/response/retrieve1
rename to module/VuFindSearch/tests/fixtures/summon/response/retrieve1
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/summon/response/retrieve2 b/module/VuFindSearch/tests/fixtures/summon/response/retrieve2
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/summon/response/retrieve2
rename to module/VuFindSearch/tests/fixtures/summon/response/retrieve2
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/summon/response/search b/module/VuFindSearch/tests/fixtures/summon/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/summon/response/search
rename to module/VuFindSearch/tests/fixtures/summon/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/summon/response/single-record b/module/VuFindSearch/tests/fixtures/summon/response/single-record
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/summon/response/single-record
rename to module/VuFindSearch/tests/fixtures/summon/response/single-record
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/worldcat/query/advanced b/module/VuFindSearch/tests/fixtures/worldcat/query/advanced
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/worldcat/query/advanced
rename to module/VuFindSearch/tests/fixtures/worldcat/query/advanced
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/worldcat/query/basic b/module/VuFindSearch/tests/fixtures/worldcat/query/basic
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/worldcat/query/basic
rename to module/VuFindSearch/tests/fixtures/worldcat/query/basic
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/worldcat/response/search b/module/VuFindSearch/tests/fixtures/worldcat/response/search
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/worldcat/response/search
rename to module/VuFindSearch/tests/fixtures/worldcat/response/search
diff --git a/module/VuFindSearch/tests/unit-tests/fixtures/worldcat/response/single-record b/module/VuFindSearch/tests/fixtures/worldcat/response/single-record
similarity index 100%
rename from module/VuFindSearch/tests/unit-tests/fixtures/worldcat/response/single-record
rename to module/VuFindSearch/tests/fixtures/worldcat/response/single-record
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/BrowZine/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/BrowZine/BackendTest.php
index c21545e13f7..df604b83b73 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/BrowZine/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/BrowZine/BackendTest.php
@@ -28,7 +28,6 @@
  */
 namespace VuFindTest\Backend\BrowZine;
 
-use InvalidArgumentException;
 use Laminas\Http\Client\Adapter\Test as TestAdapter;
 use Laminas\Http\Client as HttpClient;
 use VuFindSearch\Backend\BrowZine\Backend;
@@ -48,6 +47,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test retrieving a record (not supported).
      *
@@ -140,24 +141,6 @@ class BackendTest extends \VuFindTest\Unit\TestCase
 
     /// Internal API
 
-    /**
-     * Load a response as fixture.
-     *
-     * @param string $fixture Fixture file
-     *
-     * @return mixed
-     *
-     * @throws InvalidArgumentException Fixture files does not exist
-     */
-    protected function loadResponse($fixture)
-    {
-        $file = realpath(sprintf('%s/browzine/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return file_get_contents($file);
-    }
-
     /**
      * Return connector.
      *
@@ -169,7 +152,9 @@ class BackendTest extends \VuFindTest\Unit\TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $adapter->setResponse($this->loadResponse($fixture));
+            $adapter->setResponse(
+                $this->getFixture('browzine/response/' . $fixture, 'VuFindSearch')
+            );
         }
         $client = new HttpClient();
         $client->setAdapter($adapter);
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/BackendTest.php
index 9c3cba8ab85..dfa7e5e72d9 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/BackendTest.php
@@ -43,6 +43,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test performing an autocomplete
      *
@@ -208,11 +210,9 @@ class BackendTest extends \VuFindTest\Unit\TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/eds/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return unserialize(file_get_contents($file));
+        return unserialize(
+            $this->getFixture('eds/response/' . $fixture, 'VuFindSearch')
+        );
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/QueryBuilderTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/QueryBuilderTest.php
index 5fc2cf24a39..86aee0c025b 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/QueryBuilderTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EDS/QueryBuilderTest.php
@@ -42,6 +42,8 @@ use VuFindSearch\Backend\EDS\QueryBuilder;
  */
 class QueryBuilderTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Given a response, decode the JSON query objects for easier reading.
      *
@@ -112,11 +114,7 @@ class QueryBuilderTest extends TestCase
         $qb = new QueryBuilder();
         foreach ($tests as $test) {
             list($input, $output) = $test;
-            $q = unserialize(
-                file_get_contents(
-                    PHPUNIT_SEARCH_FIXTURES . '/eds/query/' . $input
-                )
-            );
+            $q = unserialize($this->getFixture("eds/query/$input", 'VuFindSearch'));
             $response = $qb->build($q);
             $this->assertEquals(
                 $output, $this->decodeResponse($response->get('query'))
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/BackendTest.php
index de02df81e3d..c4fa9946d09 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/BackendTest.php
@@ -44,6 +44,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test retrieving a record.
      *
@@ -148,11 +150,7 @@ class BackendTest extends \VuFindTest\Unit\TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/eit/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return file_get_contents($file);
+        return $this->getFixture("eit/response/$fixture", 'VuFindSearch');
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/QueryBuilderTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/QueryBuilderTest.php
index 9ef3d5ac234..16ba8f55d3e 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/QueryBuilderTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/EIT/QueryBuilderTest.php
@@ -42,6 +42,8 @@ use VuFindSearch\Backend\EIT\QueryBuilder;
  */
 class QueryBuilderTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test query parsing.
      *
@@ -61,9 +63,7 @@ class QueryBuilderTest extends TestCase
         foreach ($tests as $test) {
             list($input, $output) = $test;
             $q = unserialize(
-                file_get_contents(
-                    PHPUNIT_SEARCH_FIXTURES . '/eit/query/' . $input
-                )
+                $this->getFixture("eit/query/$input", 'VuFindSearch')
             );
             $response = $qb->build($q);
             $parsedQ = $response->get('query');
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/LibGuides/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/LibGuides/BackendTest.php
index 546ba7b710c..2c2b9e1058a 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/LibGuides/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/LibGuides/BackendTest.php
@@ -28,7 +28,6 @@
  */
 namespace VuFindTest\Backend\LibGuides;
 
-use InvalidArgumentException;
 use Laminas\Http\Client\Adapter\Test as TestAdapter;
 use Laminas\Http\Client as HttpClient;
 use VuFindSearch\Backend\LibGuides\Backend;
@@ -49,6 +48,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test retrieving a record (not supported).
      *
@@ -198,24 +199,6 @@ class BackendTest extends \VuFindTest\Unit\TestCase
 
     /// Internal API
 
-    /**
-     * Load a response as fixture.
-     *
-     * @param string $fixture Fixture file
-     *
-     * @return mixed
-     *
-     * @throws InvalidArgumentException Fixture files does not exist
-     */
-    protected function loadResponse($fixture)
-    {
-        $file = realpath(sprintf('%s/libguides/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return file_get_contents($file);
-    }
-
     /**
      * Return connector.
      *
@@ -227,7 +210,9 @@ class BackendTest extends \VuFindTest\Unit\TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $adapter->setResponse($this->loadResponse($fixture));
+            $adapter->setResponse(
+                $this->getFixture("libguides/response/$fixture", 'VuFindSearch')
+            );
         }
         $client = new HttpClient();
         $client->setAdapter($adapter);
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Pazpar2/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Pazpar2/BackendTest.php
index 4df4f5f215e..14f13cd2f74 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Pazpar2/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Pazpar2/BackendTest.php
@@ -44,6 +44,8 @@ use VuFindTest\Unit\TestCase;
  */
 class BackendTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test that getConnector works.
      *
@@ -133,11 +135,8 @@ class BackendTest extends TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/pazpar2/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return simplexml_load_file($file);
+        $xml = $this->getFixture("pazpar2/response/$fixture", 'VuFindSearch');
+        return simplexml_load_string($xml);
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/BackendTest.php
index 8ce5490c53d..38e840baf03 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/BackendTest.php
@@ -44,6 +44,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test retrieving a record.
      *
@@ -193,11 +195,9 @@ class BackendTest extends \VuFindTest\Unit\TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/primo/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return unserialize(file_get_contents($file));
+        return unserialize(
+            $this->getFixture("primo/response/$fixture", 'VuFindSearch')
+        );
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/ConnectorTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/ConnectorTest.php
index 66f48e3762e..6781311bfe2 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/ConnectorTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Primo/ConnectorTest.php
@@ -47,6 +47,8 @@ use VuFindSearch\Backend\Primo\Connector;
  */
 class ConnectorTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test default timeout value
      *
@@ -150,11 +152,7 @@ class ConnectorTest extends TestCase
     {
         $adapter = new TestAdapter();
         if ($fixture) {
-            $file = realpath(sprintf('%s/primo/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $file));
-            }
-            $response = file_get_contents($file);
+            $response = $this->getFixture("primo/response/$fixture", 'VuFindSearch');
             $adapter->setResponse($response);
         }
         $client = new HttpClient();
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/BackendTest.php
index 2e5960d7558..1105801807e 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/BackendTest.php
@@ -49,6 +49,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test retrieving a record.
      *
@@ -410,11 +412,9 @@ class BackendTest extends TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/solr/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $file));
-        }
-        return Response::fromString(file_get_contents($file));
+        return Response::fromString(
+            $this->getFixture("solr/response/$fixture", 'VuFindSearch')
+        );
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/ConnectorTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/ConnectorTest.php
index 29b34330edd..840469416f4 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/ConnectorTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Solr/ConnectorTest.php
@@ -48,6 +48,8 @@ use VuFindSearch\Backend\Solr\HandlerMap;
  */
 class ConnectorTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Current response.
      *
@@ -176,11 +178,8 @@ class ConnectorTest extends TestCase
     protected function createConnector($fixture = null)
     {
         if ($fixture) {
-            $file = realpath(sprintf('%s/solr/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-            if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-                throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $file));
-            }
-            $this->response = file_get_contents($file);
+            $this->response
+                = $this->getFixture("solr/response/$fixture", 'VuFindSearch');
         }
 
         $map  = new HandlerMap(['select' => ['fallback' => true]]);
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/BackendTest.php
index 955648acfd4..7c84a97687b 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/BackendTest.php
@@ -49,6 +49,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Setup method.
      *
@@ -244,11 +246,9 @@ class BackendTest extends TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/summon/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return unserialize(file_get_contents($file));
+        return unserialize(
+            $this->getFixture("summon/response/$fixture", 'VuFindSearch')
+        );
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/QueryBuilderTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/QueryBuilderTest.php
index 189960ab2a7..9c8d33dafff 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/QueryBuilderTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/Summon/QueryBuilderTest.php
@@ -42,6 +42,8 @@ use VuFindSearch\Backend\Summon\QueryBuilder;
  */
 class QueryBuilderTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test query parsing.
      *
@@ -62,9 +64,7 @@ class QueryBuilderTest extends TestCase
         foreach ($tests as $test) {
             list($input, $output) = $test;
             $q = unserialize(
-                file_get_contents(
-                    PHPUNIT_SEARCH_FIXTURES . '/summon/query/' . $input
-                )
+                $this->getFixture("summon/query/$input", 'VuFindSearch')
             );
             $response = $qb->build($q);
             $processedQ = $response->get('query');
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/BackendTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/BackendTest.php
index 68940f68398..556d7d59393 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/BackendTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/BackendTest.php
@@ -44,6 +44,8 @@ use VuFindSearch\Query\Query;
  */
 class BackendTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test retrieving a record.
      *
@@ -133,11 +135,9 @@ class BackendTest extends TestCase
      */
     protected function loadResponse($fixture)
     {
-        $file = realpath(sprintf('%s/worldcat/response/%s', PHPUNIT_SEARCH_FIXTURES, $fixture));
-        if (!is_string($file) || !file_exists($file) || !is_readable($file)) {
-            throw new InvalidArgumentException(sprintf('Unable to load fixture file: %s', $fixture));
-        }
-        return unserialize(file_get_contents($file));
+        return unserialize(
+            $this->getFixture("worldcat/response/$fixture", 'VuFindSearch')
+        );
     }
 
     /**
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/QueryBuilderTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/QueryBuilderTest.php
index 2358ed3e0b5..20bb4c34d7e 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/QueryBuilderTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/Backend/WorldCat/QueryBuilderTest.php
@@ -42,6 +42,8 @@ use VuFindSearch\Backend\WorldCat\QueryBuilder;
  */
 class QueryBuilderTest extends TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Test query parsing.
      *
@@ -62,9 +64,7 @@ class QueryBuilderTest extends TestCase
         foreach ($tests as $test) {
             list($input, $output) = $test;
             $q = unserialize(
-                file_get_contents(
-                    PHPUNIT_SEARCH_FIXTURES . '/worldcat/query/' . $input
-                )
+                $this->getFixture("worldcat/query/$input", 'VuFindSearch')
             );
             $response = $qb->build($q);
             $processedQ = $response->get('query');
@@ -81,7 +81,7 @@ class QueryBuilderTest extends TestCase
     {
         $qb = new QueryBuilder('TEST');
         $q = unserialize(
-            file_get_contents(PHPUNIT_SEARCH_FIXTURES . '/worldcat/query/basic')
+            $this->getFixture('worldcat/query/basic', 'VuFindSearch')
         );
         $response = $qb->build($q);
         $processedQ = $response->get('query');
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/child/child.txt b/module/VuFindTheme/tests/fixtures/themes/child/child.txt
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/child/child.txt
rename to module/VuFindTheme/tests/fixtures/themes/child/child.txt
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/child/css/child.css b/module/VuFindTheme/tests/fixtures/themes/child/css/child.css
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/child/css/child.css
rename to module/VuFindTheme/tests/fixtures/themes/child/css/child.css
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/child/js/extra.js b/module/VuFindTheme/tests/fixtures/themes/child/js/extra.js
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/child/js/extra.js
rename to module/VuFindTheme/tests/fixtures/themes/child/js/extra.js
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/child/js/hello.js b/module/VuFindTheme/tests/fixtures/themes/child/js/hello.js
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/child/js/hello.js
rename to module/VuFindTheme/tests/fixtures/themes/child/js/hello.js
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/child/theme.config.php b/module/VuFindTheme/tests/fixtures/themes/child/theme.config.php
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/child/theme.config.php
rename to module/VuFindTheme/tests/fixtures/themes/child/theme.config.php
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin/js/hello.js b/module/VuFindTheme/tests/fixtures/themes/mixin/js/hello.js
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin/js/hello.js
rename to module/VuFindTheme/tests/fixtures/themes/mixin/js/hello.js
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin/js/mixin.js b/module/VuFindTheme/tests/fixtures/themes/mixin/js/mixin.js
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin/js/mixin.js
rename to module/VuFindTheme/tests/fixtures/themes/mixin/js/mixin.js
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin/mixin.config.php b/module/VuFindTheme/tests/fixtures/themes/mixin/mixin.config.php
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin/mixin.config.php
rename to module/VuFindTheme/tests/fixtures/themes/mixin/mixin.config.php
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin_user/theme.config.php b/module/VuFindTheme/tests/fixtures/themes/mixin_user/theme.config.php
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/mixin_user/theme.config.php
rename to module/VuFindTheme/tests/fixtures/themes/mixin_user/theme.config.php
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/js/hello.js b/module/VuFindTheme/tests/fixtures/themes/parent/js/hello.js
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/js/hello.js
rename to module/VuFindTheme/tests/fixtures/themes/parent/js/hello.js
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/parent.txt b/module/VuFindTheme/tests/fixtures/themes/parent/parent.txt
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/parent.txt
rename to module/VuFindTheme/tests/fixtures/themes/parent/parent.txt
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/everything.phtml b/module/VuFindTheme/tests/fixtures/themes/parent/templates/everything.phtml
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/everything.phtml
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/everything.phtml
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page1.md b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page1.md
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page1.md
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page1.md
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page1.phtml b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page1.phtml
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page1.phtml
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page1.phtml
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page2_aa.phtml b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page2_aa.phtml
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page2_aa.phtml
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page2_aa.phtml
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page2_bb.phtml b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page2_bb.phtml
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page2_bb.phtml
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page2_bb.phtml
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page3.phtml b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page3.phtml
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page3.phtml
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page3.phtml
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page3_bb.phtml b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page3_bb.phtml
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page3_bb.phtml
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page3_bb.phtml
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page4.md b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page4.md
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page4.md
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page4.md
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page5_aa.md b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page5_aa.md
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page5_aa.md
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page5_aa.md
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page5_bb.md b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page5_bb.md
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page5_bb.md
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page5_bb.md
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page6.md b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page6.md
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page6.md
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page6.md
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page6_bb.md b/module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page6_bb.md
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/templates/page-locator-test/page6_bb.md
rename to module/VuFindTheme/tests/fixtures/themes/parent/templates/page-locator-test/page6_bb.md
diff --git a/module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/theme.config.php b/module/VuFindTheme/tests/fixtures/themes/parent/theme.config.php
similarity index 100%
rename from module/VuFindTheme/tests/unit-tests/fixtures/themes/parent/theme.config.php
rename to module/VuFindTheme/tests/fixtures/themes/parent/theme.config.php
diff --git a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeCompilerTest.php b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeCompilerTest.php
index faabc5051c1..b2a9ca755f9 100644
--- a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeCompilerTest.php
+++ b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeCompilerTest.php
@@ -41,12 +41,7 @@ use VuFindTheme\ThemeInfo;
  */
 class ThemeCompilerTest extends Unit\TestCase
 {
-    /**
-     * Path to theme fixtures
-     *
-     * @var string
-     */
-    protected $fixturePath;
+    use \VuFindTest\Unit\FixtureTrait;
 
     /**
      * ThemeInfo object for tests
@@ -69,8 +64,9 @@ class ThemeCompilerTest extends Unit\TestCase
      */
     public function setUp(): void
     {
-        $this->fixturePath = realpath(__DIR__ . '/../../fixtures/themes');
-        $this->info = new ThemeInfo($this->fixturePath, 'parent');
+        $this->info = new ThemeInfo(
+            $this->getFixtureDir('VuFindTheme') . 'themes', 'parent'
+        );
         $this->targetPath = $this->info->getBaseDir() . '/compiled';
         // Give up if the target directory already exists:
         if (is_dir($this->targetPath)) {
diff --git a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeInfoTest.php b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeInfoTest.php
index 4548f9da68c..7907563ea81 100644
--- a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeInfoTest.php
+++ b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/ThemeInfoTest.php
@@ -40,6 +40,8 @@ use VuFindTheme\ThemeInfo;
  */
 class ThemeInfoTest extends Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Path to theme fixtures
      *
@@ -52,7 +54,8 @@ class ThemeInfoTest extends Unit\TestCase
      */
     public function setUp(): void
     {
-        $this->fixturePath = realpath(__DIR__ . '/../../fixtures/themes');
+        $this->fixturePath
+            = realpath($this->getFixtureDir('VuFindTheme') . 'themes');
     }
 
     /**
diff --git a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/ParentTemplateTest.php b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/ParentTemplateTest.php
index 585aa6e25df..b203afc788b 100644
--- a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/ParentTemplateTest.php
+++ b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/ParentTemplateTest.php
@@ -40,6 +40,8 @@ use VuFindTheme\View\Helper\ParentTemplate;
  */
 class ParentTemplateTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Path to theme fixtures
      *
@@ -54,7 +56,8 @@ class ParentTemplateTest extends \VuFindTest\Unit\TestCase
      */
     public function setUp(): void
     {
-        $this->fixturePath = realpath(__DIR__ . '/../../../../fixtures/themes');
+        $this->fixturePath
+            = realpath($this->getFixtureDir('VuFindTheme') . 'themes');
     }
 
     /**
diff --git a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/TemplatePathTest.php b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/TemplatePathTest.php
index 869c97395bb..a7df6669e48 100644
--- a/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/TemplatePathTest.php
+++ b/module/VuFindTheme/tests/unit-tests/src/VuFindTest/View/Helper/TemplatePathTest.php
@@ -40,6 +40,8 @@ use VuFindTheme\View\Helper\TemplatePath;
  */
 class TemplatePathTest extends \VuFindTest\Unit\TestCase
 {
+    use \VuFindTest\Unit\FixtureTrait;
+
     /**
      * Path to theme fixtures
      *
@@ -54,7 +56,8 @@ class TemplatePathTest extends \VuFindTest\Unit\TestCase
      */
     public function setUp(): void
     {
-        $this->fixturePath = realpath(__DIR__ . '/../../../../fixtures/themes');
+        $this->fixturePath
+            = realpath($this->getFixtureDir('VuFindTheme') . 'themes');
     }
 
     /**
-- 
GitLab