martin88's avatar

How to delete fake images after tests

I create fake images in a model factory. When I use the factory in a test with the RefreshDatabase trait everything works, but the created images remain in the folder after the tests.

I think I am doing something wrong because creating the images makes the tests slower and for most tests, it isn't important that the image actually exists. But on the other hand, creating valid records with the factory seems to be the right thing to do.

What is the right way to handle this? How to make sure the images are also deleted after the tests? Is there a way to combine this with Storage::fake?

'image' => $faker->image('public/storage/images',640,480, null, false)
0 likes
2 replies
Tippin's avatar

@martin88 I would look into Storage::fake() and UploadedFile::fake(). In my tests where I expect images or uploads, I either store a fake uploaded file or when testing http directly, upload a fake file (works great to test validations as well)

https://laravel.com/docs/8.x/mocking#storage-fake

Example

/** @test */
public function it_removes_image_from_disk()
{
    Messenger::setProvider($this->tippin);
    Storage::fake('public');
    $directory = Messenger::getAvatarStorage('directory').'/user/'.$this->tippin->getKey();

    UploadedFile::fake()->image('avatar.jpg')->storeAs($directory, 'avatar.jpg', [
        'disk' => 'public',
    ]);

    app(DestroyMessengerAvatar::class)->execute();

    Storage::disk('public')->assertMissing($directory.'/avatar.jpg');
}

Edit: Side note, if you actually need to test against real files, you can use your setup or teardown methods to unlink() stored files, or, the built in storage/file facades to delete directories.

martin88's avatar

I used the storage fake but I had another problem then. I couldn't assert that the file which was resized with intervention exists. In this test, I decided to remove the Storage Fake and delete the files after the test manually. I know it's probably not a good way, but it's a problem for another day.

Manually removing files when using a factory seems to be really wrong. The factory looks simplified like this.

    public function definition()
    {
        return [
            'title' => $this->faker->sentence(3),
            'description' => $this->faker->paragraph(),
            'image' => $faker->image('public/storage/images',640,480, null, false),
        ];
    }

And now when I do something like this in a test, then I have two images in my storage folder.

    SomeModel::factory()->count(2)->create();

Would something like bellow this be an acceptable solution? Then the tests would be faster because no image is created and of course I don't have to delete an image manually?

    SomeModel::factory()->count(2)->create(['image'=>'nope']);

Or how can I achieve, that the Storage Fake is used when creating models with a factory?

Please or to participate in this conversation.