Generate your fixture file paths easier and less error-prone
Fixture files are a pretty common thing in web development. They allow you to produce "what should be" an end result, and assert that your test case matches that pre-produced end result.
Linking fixture files into your test cases via file paths typically becomes a messy endeavour and is prone to breaking if you ever modify the layout of your tests or fixtures. This often requires a find-and-replace solution in your code editor.
Linking fixtures this way becomes especially difficult when you're testing a Laravel package using Orchestra Testbench, since the file paths will actually be different when you run phpunit
and you cannot use base_path()
or other Laravel file path helper methods (they will return the path of the test Laravel application, not your actual packages base path).
To illustrate this, let's whip up a fictional test case that processes an audio file and "transcribes" it into a JSON file. Here's our package's file structure:
- package/
- src/
- tests/
- fixtures/
- transcription_audio.mp3
- transcription_result.json
- TranscriptionTest.php
- TestCase.php
1namespace Vendor\Package\Tests; 2 3use Vendor\Package\Transcribe; 4 5class TranscriptionTest extends TestCase 6{ 7 public function testTranscriptionWorks() 8 { 9 $audio = __DIR__.'/fixtures/transcription_audio.mp3';10 11 $result = file_get_contents(12 __DIR__.'/fixtures/transcription_result.json'13 );14 15 $this->assertEquals($result, Transcribe::audio($audio));16 }17}
There's a couple issues with the above implementation:
If we move our
fixtures
folder, our test will break.If we move
TranscriptionTest
to a sub-folder, our test will break.
To get around this, we can create a simple Fixture
static class responsible for generating file paths to where our fixtures are located, with the help of Laravel's Storage::build()
method:
1namespace Vendor\Package\Tests; 2 3use Illuminate\Support\Facades\Storage; 4 5class Fixture 6{ 7 /** 8 * Get the file path to a fixure. 9 *10 * @param string $file11 *12 * @return string13 */14 public static function path($file)15 {16 return Storage::build([17 'driver' => 'local',18 'root' => implode(DIRECTORY_SEPARATOR, [19 __DIR__, 'fixtures'20 ]),21 ])->path($file);22 }23}
Now we can re-write our above test in a much cleaner way:
1namespace Vendor\Package\Tests; 2 3use Vendor\Package\Transcribe; 4 5class TranscriptionTest extends TestCase 6{ 7 public function testTranscriptionWorks() 8 { 9 $audio = Fixture::path('transcription_audio.mp3');10 11 $result = file_get_contents(12 Fixture::path('transcription_result.json')13 );14 15 $this->assertEquals($result, Transcribe::audio($audio));16 }17}
This resolves the above issues:
If we move our
TranscriptionTest
to a sub-folder, the test will passIf we move our
fixtures
to a new folder location, we can update the new file path in one place.
Thanks for reading!