11

I would like to upload a CSV file via a Laravel API then test the upload with PHPUnit.

What would my store() function in the Controller and testCreate() function basically look like.

This is what I got so far:

<?php

use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ProspectListControllerTest extends TestCase
{

use WithoutMiddleware, DatabaseTransactions;

public function testCreate()
{

    $file = new Symfony\Component\HttpFoundation\File\UploadedFile(storage_path('/crm/data/test-file.csv'), 'test-file.csv', 'text/plain', 446, null, true);

    $this->call('POST', '/api/lists-imports/', [], [], ['csv_file' => $file]);
    $this->dump()->assertResponseOk();
  }
}

and the controller method looks like:

<?php

namespace App\Http\Controllers;

use App\ListImport;
use Illuminate\Http\Request;

class ListImportController extends Controller
{
public $model = ListImport::class;

public function store(Request $request, ListImport $importList)
{
    $request->file('importFile')->move(public_path('storage.crm.data'), $request->file('importFile')->getClientOriginalName());

    $importList->importFile = public_path('storage.crm.data') . '/' . $request->file('importFile')->getClientOriginalName();

    $importList->save();

}
}

Any help will be appreciated :)

2
  • 1
    inside testCreate function you can simulate a csv file as a string instead of upload itself no ? I was dealing with xml files I made it so on my testcases Commented Jan 24, 2017 at 7:14
  • 1
    A unit test of store() should cover if the file is stored. A better test would be to assertStringEqualsFile(). First argument should $importList->importFile and the second should be $file. This test would cover more than a the response status. Commented Feb 11, 2017 at 7:55

3 Answers 3

9

Here's an example of my feature test Laravel 6 and higher ('uploads' is my storage driver):

    use Illuminate\Http\UploadedFile;

    Storage::fake('uploads');

    $header = 'Header 1,Header 2,Header 3';
    $row1 = 'value 1,value 2,value 3';
    $row2 = 'value 1,value 2,value 3';

    $content = implode("\n", [$header, $row1, $row2]);

    $inputs = [
        'csv_file' =>
            UploadedFile::
                fake()->
                createWithContent(
                    'test.csv',
                    $content
                )
    ];


    $response = $this->postJson(
        'file-upload',
        $inputs

    );

    $response->assertOk();
Sign up to request clarification or add additional context in comments.

2 Comments

createWithontent is only available in Laravel 6 onwards
Great! createWithContent() method: there is no mention in Laravel v.6 doc, but it is defined into Illuminate\Http\Testing\FileFactory class.
0

For new Laravel version. This is how I think you should write your test. More info inside: https://laravel.com/docs/9.x/http-tests#testing-file-uploads

Don't know why but I tried another way, test passed but the original file test-file.csv got deleted so I don't chose this answer.

use Illuminate\Http\UploadedFile;
use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;

$file = new SymfonyUploadedFile(storage_path('/crm/data/test-file.csv'), 'test-file.csv', 'text/plain');
$newfile = UploadedFile::createFromBase($file, true);
$post = $this->post('/api/lists-imports/', [
    'file' => $newfile,
]);

My solution:

<?php

use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
use Illuminate\Http\UploadedFile;

class ProspectListControllerTest extends TestCase
{
    use WithoutMiddleware, DatabaseTransactions;

    public function testCreate()
    {
        $file = fopen(storage_path('/crm/data/test-file.csv'), "r") or die("Unable to open file!");
        $fileContent = fread($file, filesize(storage_path('/crm/data/test-file.csv')));
        fclose($file);
        $file = UploadedFile::fake()->createWithContent(
            'test-file.csv', $fileContent
        );
        $post = $this->post('/api/lists-imports/', [
            'file' => $file,
        ]);
        // Your assertions
    }
}

Comments

-2

There is a new way of testing file uploads in Laravel. https://laravel-news.com/testing-file-uploads-with-laravel

It is like this: (from the docs)

   public function testAvatarUpload()
{
    Storage::fake('avatars');

    $response = $this->json('POST', '/avatar', [
        'avatar' => UploadedFile::fake()->image('avatar.jpg')
    ]);

    // Assert the file was stored...
    Storage::disk('avatars')->assertExists('avatar.jpg');

    // Assert a file does not exist...
    Storage::disk('avatars')->assertMissing('missing.jpg');
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.