如何在 Laravel 5.2 中测试文件上传

Posted

技术标签:

【中文标题】如何在 Laravel 5.2 中测试文件上传【英文标题】:How to test file upload in Laravel 5.2 【发布时间】:2016-07-24 07:38:11 【问题描述】:

我正在尝试测试上传 API,但每次都失败:

测试代码:

$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']));

文件路径为/public/uploads/test/34610974.jpg

这是控制器中的我的上传代码:

$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]);

我应该如何在 Laravel 5.2 中测试文件上传?如何使用call方法上传文件?

【问题讨论】:

Laravel 关于伪造文件上传的文档 (5.8):laravel.com/docs/5.8/http-tests#testing-file-uploads 【参考方案1】:

我认为这是最简单的方法

$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); 

我认为在测试中删除上传文件的最佳方法是使用 tearDownAfterClass 静态方法, 这将删除所有上传的文件

use Illuminate\Filesystem\Filesystem;

public static function tearDownAfterClass():void
        $file=new Filesystem;
        $file->cleanDirectory("storage/app/public/images");

【讨论】:

【参考方案2】:

laravel 文档为您何时想要测试假文件提供了答案。当您想在 laravel 6 中使用真实文件进行测试时,您可以执行以下操作:

namespace Tests\Feature;

use Illuminate\Http\UploadedFile;
use Tests\TestCase;

class UploadsTest extends TestCase

    // This authenticates a user, useful for authenticated routes
    public function setUp(): void
    
        parent::setUp();
        $user = User::first();
        $this->actingAs($user);
        

    public function testUploadFile()
    
        $name = 'file.xlsx';
        $path = 'absolute_directory_of_file/' . $name;
        $file = new UploadedFile($path, $name, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', null, true);
        $route = 'route_for_upload';
        // Params contains any post parameters
        $params = [];
        $response = $this->call('POST', $route, $params, [], ['upload' => $file]);
        $response->assertStatus(200);
      


【讨论】:

【参考方案3】:

在 Laravel 5.4 中,你也可以使用 \Illuminate\Http\UploadedFile::fake()。下面是一个简单的例子:

/**
 * @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());

如果你想伪造不同的文件类型,你可以使用

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

更多信息直接在Laravel Documentation.

【讨论】:

但是如果只询问特定的 MIME 类型如 mp3,create() 方法不会通过验证...【参考方案4】:

您可以在link找到此代码

设置

/**
 * @param      $fileName
 * @param      $stubDirPath
 * @param null $mimeType
 * @param null $size
 *
 * @return  \Illuminate\Http\UploadedFile
 */
public static function getTestingFile($fileName, $stubDirPath, $mimeType = null, $size = null)

    $file =  $stubDirPath . $fileName;

    return new \Illuminate\Http\UploadedFile\UploadedFile($file, $fileName, $mimeType, $size, $error = null, $testMode = true);

用法

    $fileName = 'orders.csv';
    $filePath = __DIR__ . '/Stubs/';

    $file = $this->getTestingFile($fileName, $filePath, 'text/csv', 2100);

文件夹结构:

- MyTests
  - TestA.php
  - Stubs
    - orders.csv

【讨论】:

【参考方案5】:

创建UploadedFile 的实例时,将最后一个参数$test 设置为true

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

这是一个工作测试的简单示例。它希望您在tests/stubs 文件夹中有一个存根test.png 文件。

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 测试/UploadTest.php Sebastian Bergmann 和贡献者的 PHPUnit 4.8.24。 . 时间:2.97 秒,内存:14.00Mb 好的(1 个测试,3 个断言)

【讨论】:

应该可以,但是不行。 $request->file('photo') 确实有 UploadFile 对象,但是这个对象中的$test 有它的默认值false。奇怪,因为新的 UploadedFile 有 $test = true 参数。 以上答案对于 > 5.2.14 是不够的。你能在这里找到正确的答案:***.com/questions/36857800/… 应该是$file = new UploadedFile($path, $name, 'image/png', filesize($path), null, true); 对于Symfony 4.1,正确的实现是$file = new UploadedFile($path, $name, 'image/png', null, true);

以上是关于如何在 Laravel 5.2 中测试文件上传的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 laravel 和 phpunit 测试文件上传?

如何在laravel 5.2中为每个文件添加用户ID以供下载?

Connection.php 第 729 行中的 QueryException:SQLSTATE[23000]:Laravel 5.2

在 laravel 5.4 中测试文件上传时出错

如何在没有 SSH 的情况下在 GoDaddy 共享主机中托管 Laravel 5.2?

Laravel 5.2将公共文件夹更改为共享服务器上的public_html [重复]