【问题标题】:Mocking Laravel custom validation rule class not working模拟 Laravel 自定义验证规则类不起作用
【发布时间】:2020-05-08 05:31:46
【问题描述】:

我正在表单提交中实施新的自定义验证规则。但我想绕过单元测试中的验证规则。下面是验证规则和单元测试类的简化。我错过了什么?

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Captcha implements Rule
{
    public function passes($attribute, $value)
    {
        // assuming will always return false in testing
        // works fine when true
        return false; 
    }

    public function message()
    {
        return 'Captcha error! Try again later or contact site admin.';
    }
}
use Tests\TestCase;
use App\Rules\Captcha;

class RegistrationTest extends TestCase {

    public test_user_registration()
    {
        $this->mock(Captcha::class, function ($mock) {
            $mock->shouldReceive('passes')->andReturn(true);
        });

        $response = $this->post(route('tenant.register'), [
            'g-recaptcha-response' => 1,
            'email' => 'user@example.com',
            'password' => 'secret',
        ]);

        $this->assertEquals(1, User::all()->count());
     }
} 

编辑:还包括 FormRequestController 文件

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Rules\Captcha;

class NewUserRequest extends FormRequest {

    public function rules()
    {
        return [
            'name' => ['required', new Captcha]
        ];
    }
}
...

public function postRegister(NewUserRequest $request) {

...

EDIT II:似乎是 Laravel 本身的一个错误;

尝试了提供的解决方案,但仍然无法正常工作

【问题讨论】:

  • 您的代码将模拟实例注册到容器中(通过->mock() 隐式注册)。您是否也从容器中检索它? app(Captcha::class) 在您的代码中?如果您不这样做,而只是执行new Captcha,那么它将无法正常工作。 laravel.com/docs/6.x/validation#using-rule-objects 的文档给出了这个例子,这样就不能模拟了。

标签: laravel-5 phpunit


【解决方案1】:

该类必须通过 Laravel 服务容器实例化才能被模拟。完成此操作(在这种情况下)的最佳方法是将new Captcha 更改为app(Captcha::class)

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Rules\Captcha;

class NewUserRequest extends FormRequest {

    public function rules()
    {
        return [
            'name' => ['required', app(Captcha::class)]
        ];
    }
}

我建议不要告诉规则本身根据环境改变其行为,因为当您试图弄清楚为什么验证码在开发环境中没有做任何事情时,这可能会导致一些混乱,但是生产失败。

【讨论】:

  • 老兄,它确实有效,虽然看起来仍然是一种解决方法,但仍然比我的解决方案更好。
  • 它看起来确实是一种解决方法,但它看起来非常聪明并且可以完成工作。唯一的事情是,只有在您的规则不需要任何参数时,您才能执行此操作。 +1
【解决方案2】:

似乎是 Laravel 中长期存在的 bug,所以解决方法是不使用 Mock。因此,当存在testing 环境时,我将绕过Rule 类。

if (app()->environment() === 'testing')
    return true;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 2017-04-11
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-12
    相关资源
    最近更新 更多