How to test file upload in Laravel 5.2

28,920

Solution 1

When you create an instance of UploadedFile set the last parameter $test to true.

$file = new UploadedFile($path, $name, filesize($path), 'image/png', null, true);
                                                                           ^^^^

Here is a quick example of a working test. It expects that you have a stub test.png file in tests/stubs folder.

class UploadTest extends TestCase
{
    public function test_upload_works()
    {
        $stub = __DIR__.'/stubs/test.png';
        $name = str_random(8).'.png';
        $path = sys_get_temp_dir().'/'.$name;

        copy($stub, $path);

        $file = new UploadedFile($path, $name, filesize($path), 'image/png', null, true);
        $response = $this->call('POST', '/upload', [], [], ['photo' => $file], ['Accept' => 'application/json']);

        $this->assertResponseOk();
        $content = json_decode($response->getContent());
        $this->assertObjectHasAttribute('name', $content);

        $uploaded = 'uploads'.DIRECTORY_SEPARATOR.$content->name;
        $this->assertFileExists(public_path($uploaded));

        @unlink($uploaded);
    }
}
➔ phpunit tests/UploadTest.php
PHPUnit 4.8.24 by Sebastian Bergmann and contributors.

.

Time: 2.97 seconds, Memory: 14.00Mb

OK (1 test, 3 assertions)

Solution 2

In Laravel 5.4 you can also use \Illuminate\Http\UploadedFile::fake(). A simple example below:

/**
 * @test
 */
public function it_should_allow_to_upload_an_image_attachment()
{
    $this->post(
        action('AttachmentController@store'),
        ['file' => UploadedFile::fake()->image('file.png', 600, 600)]
    );

    /** @var \App\Attachment $attachment */
    $this->assertNotNull($attachment = Attachment::query()->first());
    $this->assertFileExists($attachment->path());
    @unlink($attachment->path());
}

If you want to fake a different file type you can use

UploadedFile::fake()->create($name, $kilobytes = 0)

More information directly on Laravel Documentation.

Solution 3

I think this is the easiest way to do it

$file=UploadedFile::fake()->image('file.png', 600, 600)];
$this->post(route("user.store"),["file" =>$file));

$user= User::first();

//check file exists in the directory
Storage::disk("local")->assertExists($user->file); 

and I think the best way to delete uploaded files in the test is by using tearDownAfterClass static method, this will delete all uploaded files

use Illuminate\Filesystem\Filesystem;

public static function tearDownAfterClass():void{
        $file=new Filesystem;
        $file->cleanDirectory("storage/app/public/images");
}
Share:
28,920
Ramin Omrani
Author by

Ramin Omrani

I am a software developer based in Rome, Italy, with a particular focus on the web. I became passionate about programming at the age of 14 when I was a member of the Robocup students' team of Tehran. Since then, my passion for learning new tools and trends in programming has never stopped.

Updated on August 17, 2020

Comments

  • Ramin Omrani
    Ramin Omrani almost 4 years

    Im trying to test an upload API but it fails every time:

    Test Code :

    $JSONResponse = $this->call('POST', '/upload', [], [], [
        'photo' => new UploadedFile(base_path('public/uploads/test') . '/34610974.jpg', '34610974.jpg')
    ]);
    
    $this->assertResponseOk();
    $this->seeJsonStructure(['name']);
    
    $response = json_decode($JSONResponse);
    $this->assertTrue(file_exists(base_path('public/uploads') . '/' . $response['name']));
    

    file path is /public/uploads/test/34610974.jpg

    Here is My Upload code in a controller :

    $this->validate($request, [
        'photo' => 'bail|required|image|max:1024'
    ]);
    
    $name = 'adummyname' . '.' . $request->file('photo')->getClientOriginalExtension();
    
    $request->file('photo')->move('/uploads', $name);
    
    return response()->json(['name' => $name]);
    

    How should I test file upload in Laravel 5.2? How to use call method to upload a file?

  • schellingerht
    schellingerht about 8 years
    That should work, but it doesn't. $request->file('photo') has indeed the UploadFile object, but $test in this object has its default value false. Strange, because the new UploadedFile has the $test = true parameter.
  • schellingerht
    schellingerht about 8 years
    The answer above is not enough for > 5.2.14. The right answer could you find here: stackoverflow.com/questions/36857800/…
  • Hanson
    Hanson about 7 years
    It should be $file = new UploadedFile($path, $name, 'image/png', filesize($path), null, true);
  • Syl
    Syl almost 7 years
    But the create() method does not pass the validation if you only ask a specific MIME type such as mp3...
  • Fanan Dala
    Fanan Dala over 3 years
    For Symfony 4.1 the correct implementation is $file = new UploadedFile($path, $name, 'image/png', null, true);