问题
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