如何在 laravel PHPunit 测试中触发异常

问题描述 投票:0回答:1

我在尝试测试涉及数据库交互的 Laravel 控制器中的异常处理时遇到问题。具体来说,我想在控制器的 store 方法中测试异常的 catch 块。存储方法如下所示:

public function store(Request $request, Pipeline $pipeline)
{
    try {
        $request->validate([
            "name" => ["required", "max:512"],
            "stage" => ["required", "in:".Stage::toCSV()],
        ]);

        // Database interaction here (e.g., MyModel::create())

        return response()->json(["message" => trans("round.created")], 201);
    } catch (\Exception $e) {
        Log::error('Exception in MyController@store: ' . $e->getMessage());
        Log::error('Stack trace: ' . $e->getTraceAsString());
        return redirect()->back()->banner(trans('error'));
    }
}

这是我迄今为止尝试过的

$this->mock(\App\Models\MyModel::class, function ($mock) {
            $mock->shouldReceive('create')
                ->once()
                ->andThrow(new \Exception('Simulated exception'));
        });
$this->mock(\Exception::class, function ($mock) {
            $mock->shouldReceive('getMessage')->andReturn('Mocked exception message');
        });

任何关于如何正确模拟数据库交互以模拟异常并测试 catch 块的建议或指导将不胜感激。

谢谢!

php laravel testing phpunit
1个回答
0
投票

在 Laravel 控制器的 store 方法中测试异常的 catch 块的最佳方法是模拟数据库交互,以便引发异常。为此,您需要模拟 MyModel 类以在创建方法调用期间引发异常 为此,我建议将模型作为控制器的依赖项注入,这样您就可以创建一个模拟模型并通过它并测试其功能

use App\Models\MyModel;

class MyController extends Controller
{
    public function store(Request $request, MyModel $model, Pipeline $pipeline)
    {
        try {
            $request->validate([
                "name" => ["required", "max:512"],
                "stage" => ["required", "in:".Stage::toCSV()],
            ]);

            // Use the injected model for database interaction
            $model->create([
                // Your data here
            ]);

            return response()->json(["message" => trans("round.created")], 201);
        } catch (\Exception $e) {
            Log::error('Exception in MyController@store: ' . $e->getMessage());
            Log::error('Stack trace: ' . $e->getTraceAsString());
            return redirect()->back()->banner(trans('error'));
        }
    }
}

或者您可以采用基于服务的方法。 在这两种情况下,您都可以模拟模型/服务,然后将模拟的依赖项注入控制器并测试它

要创建模拟,您可以使用模拟构建器或模拟或

匿名类

$modelMock = new class extends MyModel {
            public static function create(array $attributes = [])
            {
                // Throw an exception when create is called
                throw new \Exception('Simulated exception');
            }
        };
© www.soinside.com 2019 - 2024. All rights reserved.