Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test file upload with laravel and phpunit?

I'm trying to run this functional test on my laravel controller. I would like to test image processing, but to do so I want to fake image uploading. How do I do this? I found a few examples online but none seem to work for me. Here's what I have:

public function testResizeMethod()
{
    $this->prepareCleanDB();

    $this->_createAccessableCompany();

    $local_file = __DIR__ . '/test-files/large-avatar.jpg';

    $uploadedFile = new Symfony\Component\HttpFoundation\File\UploadedFile(
        $local_file,
        'large-avatar.jpg',
        'image/jpeg',
        null,
        null,
        true
    );


    $values =  array(
        'company_id' => $this->company->id
    );

    $response = $this->action(
        'POST',
        'FileStorageController@store',
        $values,
        ['file' => $uploadedFile]
    );

    $readable_response = $this->getReadableResponseObject($response);
}

But the controller doesn't get passed this check:

elseif (!Input::hasFile('file'))
{
    return Response::error('No file uploaded');
}

So somehow the file isn't passed correctly. How do I go about this?

like image 543
Jasper Kennis Avatar asked Oct 22 '15 12:10

Jasper Kennis


3 Answers

For anyone else stumbling upon this question, you can nowadays do this:

    $response = $this->postJson('/product-import', [
        'file' => new \Illuminate\Http\UploadedFile(resource_path('test-files/large-avatar.jpg'), 'large-avatar.jpg', null, null, null, true),
    ]);

UPDATE

In Laravel 6 the constructor of \Illuminate\Http\UploadedFile Class has 5 parameters instead of 6. This is the new constructor:

    /**
     * @param string      $path         The full temporary path to the file
     * @param string      $originalName The original file name of the uploaded file
     * @param string|null $mimeType     The type of the file as provided by PHP; null defaults to application/octet-stream
     * @param int|null    $error        The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
     * @param bool        $test         Whether the test mode is active
     *                                  Local files are used in test mode hence the code should not enforce HTTP uploads
     *
     * @throws FileException         If file_uploads is disabled
     * @throws FileNotFoundException If the file does not exist
     */
    public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, $test = false)
    {
        // ...
    }

So the above solution becomes simply:

$response = $this->postJson('/product-import', [
        'file' => new \Illuminate\Http\UploadedFile(resource_path('test-files/large-avatar.jpg'), 'large-avatar.jpg', null, null, true),
    ]);

It works for me.

like image 141
Mikael Avatar answered Nov 18 '22 18:11

Mikael


Docs for CrawlerTrait.html#method_action reads:

Parameters
string $method
string $action
array $wildcards
array $parameters
array $cookies
array $files
array $server
string $content

So I assume the correct call should be

$response = $this->action(
    'POST',
    'FileStorageController@store',
    [],
    $values,
    [],
    ['file' => $uploadedFile]
);

unless it requires non-empty wildcards and cookies.

like image 12
Alex Blex Avatar answered Nov 18 '22 20:11

Alex Blex


The best and Easiest way : First Import the Necessary things

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

Then make a fake file to upload.

Storage::fake('local');
$file = UploadedFile::fake()->create('file.pdf');

Then make a JSON Data to pass the file. Example

$parameters =[
            'institute'=>'Allen Peter Institute',
            'total_marks'=>'100',
            'aggregate_marks'=>'78',
            'percentage'=>'78',
            'year'=>'2002',
            'qualification_document'=>$file,
        ];

Then send the Data to your API.

$user = User::where('email','[email protected]')->first();

$response = $this->json('post', 'api/user', $parameters, $this->headers($user));

$response->assertStatus(200);

I hope it will work.

like image 9
Inamur Rahman Avatar answered Nov 18 '22 18:11

Inamur Rahman