coderego's avatar

Testing with file uploads

Hello, I am trying to test file uploads and hitting a snag. How do I write a test using faker to store a file that is never really uploaded?

The error I am getting is:

..EFEEEEEEEE                                                      12 / 12 (100%)

Time: 1.49 seconds, Memory: 10.00MB

There were 9 errors:

1) Tests\Feature\CreateVideosTest::an_authenticated_user_can_create_new_videos
Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function store() on null

Here's the code:

*Controller

    public function store(Request $request)
    {
        //store video
        $file = $request->file('video')->store('videos');

        $video = Video::create([
            'user_id' => auth()->id(),
            'title' => request('title'),
            'body' => request('body'),
            'path' => $file
        ]);

        return redirect($video->link());
    }

*Model Factory

$factory->define(App\Video::class, function($faker)
{

    $file = $faker->file($sourceDir='/tmp', $targetDir='/tmp/tmp2', false);

    return [
        'user_id' => function() {
            return factory('App\User')->create()->id;
        },
        'title' => $faker->sentence,
        'body' => $faker->paragraph,
        'video' => $file
    ];
});

*Test

   /** @test */
   function an_authenticated_user_can_create_new_videos()
   {
       $this->signIn();

       $video = make('App\Video');

       $this->post('/videos', $video->toArray());

       $this->get($video->link())
           ->assertSee($video->title);

   }
0 likes
5 replies
jlrdw's avatar

Wouldn't it be easier just to actually upload a file and verify it works.

coderego's avatar

Of course, I have, and it does. I still want to have testing for it though.

ohffs's avatar

Could you get away with using the storage fake? If not and you actually want to test the file is written to disk, in the past I've done something like :

$file = './tests/data/myfile.dat';

// call post with the request data

$dbFile = FileModel::first();
$original = file_get_contents($file);
$new = file_get_contents($dbFile->path);
unlink($dbFile->path);

$this->assertEquals($original, $new);

Edit: Ah - misread your question! I think you're call to ->post isn't actually posting the data correctly - have a look at something like http://stackoverflow.com/questions/36857800/laravel-5-2-testing-uploadedfile-misses-the-test-value-after-post-bug for the way to do it.

coderego's avatar
coderego
OP
Best Answer
Level 6

I've updated the test to this. It works, but it is pretty gross...

       $this->signIn();

       $video = make('App\Video');
       $rawVideo = $video->toArray();

       $path  = '/tmp/test.mp4';
       $file = new \Symfony\Component\HttpFoundation\File\UploadedFile ($path, null, null, null, null, true);
       
       $rawVideo['video'] = $file;
       $this->post('/videos', $rawVideo);

       $this->get($video->link())
           ->assertSee($video->title);
ohffs's avatar

Yep - it's annoyingly awkward to test a real file upload :-/

Please or to participate in this conversation.