【问题标题】:Test Laravel Controller's try catch测试 Laravel Controller 的 try catch
【发布时间】:2019-08-06 01:52:32
【问题描述】:

我正在使用 Laravel 5.7 并且有这个控制器

public function upload(Request $request)
{
    $fileData   = $request->getContent();
    $fileName   = uniqid().'.xlsx';

    try {
        // save file locally
        Storage::disk('local')->put($fileName, $fileData);

        // dispatch to queue
        AnyJob::dispatch($fileName);

        // insert in import_statuses table for status checking
        AnyModel::create([
            'job_id'  => $fileName
        ]);

    } catch (\Exception $e) {
        error_log($e);

        return response()->json([
            'error' => 'Could not save file or queue not found.'
        ], 500);
    }

    return response()->json([
        'status' => 'OK',
        'jobId'  => $fileName,
    ]);
}

我正在尝试创建一个进入 catch 的测试,但我无法让它工作。

我已经尝试模拟 Storage 并期望调用方法 diskput,但它总是抱怨调用了其他方法而不是预期。

我也尝试过以多种方式模拟 AnyJobAnyModel,但这似乎不会影响 $this->post 发出的请求。

这是我现在的测试方法:

public function testUploadException()
{
    $xlsxFile = UploadedFile::fake()->create('test.xlsx', 100);

    // ignore Storage and Job real work
    \Illuminate\Support\Facades\Storage::fake();
    $this->withoutJobs();

    $mock = Mockery::mock('\App\AnyModel');
    $mock
        ->shouldReceive('create')->times(3)
        ->andThrow(new \Exception('any error'));

    $this->app->instance('\App\AnyModel', $mock);

    $response = $this
        ->withHeaders(['content-type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'])
        ->post('/api/upload', [$xlsxFile]);

    $response
        ->assertStatus(500)
        ->assertJson([
            'error' => 'Could not save file or queue not found.'
        ]);
}

以及它返回的内容

root@3e5d84a4db42:/application/api# vendor/bin/phpunit 
PHPUnit 7.5.4 by Sebastian Bergmann and contributors.

....F                                                               5 / 5 (100%)

Time: 2.62 seconds, Memory: 20.00MB

There was 1 failure:

1) Tests\Feature\UploadTest::testUploadException
Expected status code 500 but received 200.
Failed asserting that false is true.

/application/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:133
/application/api/tests/Feature/UploadTest.php:50

FAILURES!
Tests: 5, Assertions: 8, Failures: 1.

【问题讨论】:

  • 你使用的是什么版本的 Laravel?
  • @RossWilson 5.7

标签: laravel testing mocking automated-tests mockery


【解决方案1】:

这不起作用的主要原因是您没有从 IoC 解析模型,例如使用app() 或依赖注入。这将适用于外观,但不适用于 Eloquent 模型。

您可以将控制器方法定义更改为以下内容以从容器中解析类:

public function upload(Request $request, AnyModel $anyModel)

那么您对create 的调用将是:

$anyModel->create([
    'job_id'  => $fileName
]);

您的测试中也存在一些问题:

  1. 类的完全限定名称是'App\AnyModel' 而不是'\App\AnyModel'。我建议使用::class 而不是使用字符串,即AnyModel::class(确保您已导入该类)。
  2. 您似乎只调用了一次create(),因此使用->times(3) 会引发错误。

【讨论】:

  • 当我试图从单元测试中获取错误时,我不小心离开了times(3)。谢谢你的回答
【解决方案2】:

除了@RossWilson 谈到的使用 IoC 之外,我还发现我可以通过使用陷入 catch 块中

Storage::shouldReceive('disk')->andThrow('error');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 2020-02-24
    • 1970-01-01
    • 2020-09-14
    相关资源
    最近更新 更多