1

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

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

以下来自我的 Request 类(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 上是否有密码,而不是在其他方法上设置。

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

  • POST to route 在数据库中创建一个用户并且在会话中没有错误
  • PATCH to route 不会更改密码,即使它已在数据集中传递。

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

提前致谢

4

1 回答 1

3

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

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);
    }
}
于 2020-06-17T12:39:56.480 回答