I make a service and allow users upload their avatar.
I want to test this feature if run correctly or not, however I cannot get the random file name when using $request->avatar->store('avatar') in controller when testing, how can I resolve it?
Make avatar upload post route.
routes/web.php
<?php
Route::post('/avatar', function (\Illuminate\Http\Request $request) {
if ($request->file('avatar')->isValid()) {
return $request->avatar->store('avatar');
}
throw new Exception('Upload file is not valid');
});
Make feature testing
tests/Feature/UploadAvatarTest.php
<?php
namespace Tests\Feature;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class UploadAvatarTest extends TestCase
{
public function test_upload_avatar()
{
Storage::fake('local');
$this->post('/avatar', [
'avatar' => UploadedFile::fake()->image('avatar.jpg'),
]);
Storage::disk('local')->assertExists('avatar/avatar.jpg');
}
}
execute vendor/bin/phpunit
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.
.F. 3 / 3 (100%)
Time: 125 ms, Memory: 12.00MB
There was 1 failure:
1) Tests\Feature\UploadAvatarTest::test_upload_avatar
Unable to find a file at path [avatar/avatar.jpg].
Failed asserting that false is true.
/Projects/testProject/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php:50
/Projects/testProject/tests/Feature/UploadAvatarTest.php:19
FAILURES!
Tests: 3, Assertions: 3, Failures: 1.
The store method hash the filename so it's not avatar.jpg anymore, use the second parameter of storeAs method if you do not want to change the name of the file or recover the generated filename in the response.
In my application, I want to change the file name by laravel store method at UploadedFile but the file name will not be responsed at the page.
However I cannot get the random file name when unit testing, is there any solution of it?
The store method return the filename so you should have it in the response because you are returning the store result.
Your first problem is with hashName. This will not work checking this name in your test. You can use the storeAs() method in the controller to change the name to be "avatar" getClientOriginalName() on your test cases. I did it by including a flag to keep the original name instead of using hashName.
By doing this your test should work. Also, remember though that you may want to use a "test" location instead of "avatar" because you may want to delete the files for test at some time if space is an issue. On the other hand, if you use the Storage::fake() then you need to make sure you update your filesystems.php to default the correct storage location for testing.
Personally I like the storeAs() method because I know exactly what I am testing for in my test, but testing against hashName is just as elegant too.
Please reopen this. This is definietly an issue!
You cant except for the sake of tests that we use storeAs() instead of store(). I want that the framework generate a random filename and test againts is.
The Storage::fake() call should ensure, that you can test file uploads even if you using store() with random filename generation.
for me it's not an issue at all, the generated filename is returned, so you can test it easily.
What if the response doesn't contain the generated filename? It is bad practice to do something special in your tests that is only there to get the tests to pass, since then you are not really testing the code and it defeats the whole purpose.
Most helpful comment
What if the response doesn't contain the generated filename? It is bad practice to do something special in your tests that is only there to get the tests to pass, since then you are not really testing the code and it defeats the whole purpose.