Mocking Laravel custom validation rule class not working

こ雲淡風輕ζ 提交于 2020-02-06 07:56:52

问题


I'm implementing a new custom validation rule in form submit. But I want to bypass the validation rule in unit testing. Below is the simplified of the validation rule and unit test class. What am I missing?

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());
     }
} 

EDIT: included FormRequest and Controller file as well

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: seems like a bug in Laravel itself;

  • https://github.com/laravel/framework/issues/28468
  • https://github.com/laravel/framework/issues/19450
  • https://github.com/laravel/framework/issues/25041

tried the provided solutions but still not working


回答1:


The class must be instantiated through Laravels service container in order for it to be mocked. The best way to accomplish this (in this situation) is to simply change new Captcha to 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)]
        ];
    }
}

I would advise against telling the rule itself to change its behaviors based on environments as that could result in a bit of confusion down the line when you are trying to figure out why the captcha doesn't do anything in dev environments but is failing in production.




回答2:


Seems like an existing bug in Laravel for a long time, so the workaround is to not using Mock. So I will just bypass in Rule class when testing environment is present.

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


来源:https://stackoverflow.com/questions/59853235/mocking-laravel-custom-validation-rule-class-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!