Laravel 5.2 | Testing UploadedFile Misses the $tes

2019-01-11 10:43发布

问题:

Update 2016/04/26 11:30 GMT+2 Workaround

Since Laravel 5.2.15, the $test parameter is removed, but there is no clear reason, because Symfony's UploadedFile still has the $test parameter.

A workaround is to use Laravel 5.2.14 provisionally.

Update 2016/04/26 11:00 GMT+2

Laravel's own UploadedFile doesn't pass the $test parameter. See these resources:

  • https://github.com/laravel/framework/issues/12620
  • https://github.com/laravel/framework/commit/5062a9b42632e55ee90b7397141c0b12622447e1

I know, there's another question: How to test file upload in Laravel 5.2, but the marked answer doesn't work for me.

Test Case

I create an instance of Symfony's UploadedFile class and I set $test to true. I post the file to file/upload.

class FileControllerTest extends TestCase
{
    use \Illuminate\Foundation\Testing\DatabaseTransactions;

    private $file;

    public function setUp()
    {
        parent::setUp();

        $this->file = new Symfony\Component\HttpFoundation\File\UploadedFile(
            public_path() . '/examples/example.jpg',
            'example.jpg',
            'image/jpeg',
            filesize(public_path() . '/examples/example.jpg'),
            null,
            true // for $test
        );
    }

    /** @test */
    public function it_uploads_a_valid_file()
    {
        var_dump($this->file); // $test = true
        $this->call('POST', 'file/upload', [], [], ['file' => $this->file],
            ['accept' => 'application/json']);

        $this->assertResponseOk();
    }
}

Controller

namespace App\Http\Controllers;

class FileController extends Controller
{
    public function upload(Request $request)
    {
        var_dump($request->file('file')); // $test = false

        return [];
    }
}

Problem

  • The file to post has the argument true for $test
  • The posted file arrives in upload()
  • $request->file('file') contains the right arguments, but

    $test is false

It seems the argument $test is not past by the post call. Is this a bug?

回答1:

Explanation

This is really interesting thing. You've noticed already a lot of when creating this post (if anyone has the problem should read it carefully).

In this commit as you already mentioned $testing parameter was removed and code of classes was simplified removing Reflection to get testing property value of Symfony\Component\HttpFoundation\File\UploadedFile.

And now the tricky thing is that depending on what you are testing, you might event not notice the change and everything might work but in some cases it won't and you won't really know why.

For example everything might work - file will be uploaded without a problem, but if you add into your Request class for instance mimes rule like so:

'logo' => ['mimes:jpeg,png'],

it will fail telling you the file has invalid mime (this is because internally it will be also verified if file was really uploaded and in case of tests in fact it's not the same as real upload).

The solution is looking again at what was really changed into the commit and how the method look like. In this file instance of uploaded file is returned like so:

 return $file instanceof static ? $file : new static(
            $file->getRealPath(), $file->getClientOriginalName(), $file->getClientMimeType(),
            $file->getClientSize(), $file->getError()
        );

so in case if the file is instance of this class it will return this instance unmodified, otherwise it will create now object without passing $testing argument to class constructor.

Solution

So to solve this, when testing file uploads you should not use

\Symfony\Component\HttpFoundation\File\UploadedFile

class anymore. You should now use

\Illuminate\Http\UploadedFile

to don't get any strange issues when testing file uploads (of course you should still pass to this object constructor true as $testing parameter but now it will be used later without a problem)