如何对 laravel 表单请求的 prepareForValidation 进行单元测试?

How to unit test prepareForValidation on laravel Form Request?

背景: 在我的Laravel项目中,我正在实现管理员可以创建用户的用户创建功能。在创建用户期间,我设置了一个随机密码(不是输入)并向用户发送密码重置电子邮件。在我的架构中,密码字段不可为空(我不希望数据库中有任何没有密码的用户)。

我正在使用表单请求来实现控制器验证,并使用 prepareForValidation 在 POST 上设置随机密码,但在 [=31= 上将密码设置为 null ]PATCH 因为我不希望在用户更新事件时更新密码。 (管理员可以更新用户配置文件,但不能更新密码。)验证规则 'sometimes' 处理这两种情况。

以下来自我的请求 class(rulesprepareForValidation 方法)。

class AdminUserRequest extends FormRequest
{
    public function rules()
    {
        return [
            ...
            'password' => [
                'sometimes',
                'required',
                'min:8',
            ],
            ...
        ];
    }

    /**
     * Prepare the data for validation.
     *
     * @return void
     */
    protected function prepareForValidation()
    {
        if ($this->getMethod() == 'POST') {

            $this->merge([
                'password' => Hash::make(Str::random(10)),
            ]);
        } else {
            $this->offsetUnset('password');
        }
    }
}

问题: 我的问题是在表单请求中单元测试 prepareForValidation 功能的最佳方法是什么。

应该测试请求数据集在 POST 上有密码并且没有在其他方法上设置。

当然我可以做功能测试来覆盖案例

但我想知道是否有办法对此进行单元测试。以及如何去做。

提前致谢

它可能是这样的(我没有嘲笑 request 并对其安排期望 - 而是保持简单)。最后一个方法用于 private/protected 方法调用 classes。这可以移至 TestCase class 以供将来使用。

class AdminUserRequestTest extends TestCase
{
    /**
     * @test
     * @covers ::prepareForValidation
     */
    function it_should_add_password_when_it_is_post_method()
    {
        $request = new AdminUserRequest();
        $request->setMethod('POST');
        $hashedPassword = 'a1b2c3d4e5';

        Hash::shouldReceive('make')->andReturn($hashedPassword);
        $this->invokeMethod($request, 'prepareForValidation');

        $this->assertSame($request->get('password'), $hashedPassword);
    }

    /**
     * @test
     * @covers ::prepareForValidation
     */
    function it_should_unset_password_when_it_is_not_post_method()
    {
        $request = new AdminUserRequest();
        $request->setMethod('PUT'); // it could be something else besides POST
        $this->invokeMethod($request, 'prepareForValidation');

        $this->assertFalse($request->has('password'));
    }

    protected function invokeMethod(&$object, $methodName, array $parameters = [])
    {
        $reflection = new ReflectionClass(get_class($object));
        $method = $reflection->getMethod($methodName);
        $method->setAccessible(true);

        return $method->invokeArgs($object, $parameters);
    }
}