我想模拟自定义验证规则(例如 App\Rules\SomeRule)。但是当我运行测试时,它给出了
Mockery\Exception\InvalidCountException: Method...should be called
exactly 1 times but called 0 times.
我已经阅读了 Laravel 的文档关于模拟、关于自定义验证规则、服务容器、服务提供商,我不明白为什么我没有成功地模拟规则。
我读了这个线程,但我很难将它与我的问题联系起来,即“如何测试我的应用程序是否正在使用此规则”。或者这是我无法测试的东西?
这是我的规则
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class SomeRule implements Rule
{
public function passes($attribute, $value)
{
// some logic, returns TRUE if valid.
}
public function message()
{
//
}
}
我的控制器
namespace App\Http\Controllers;
use App\Rules\SomeRule;
use Illuminate\Http\Request;
class LoanController extends Controller
{
public function store(Request $request)
{
$request->validate([
'email' => ['required', new SomeRule]
]);
// ...insert in database, return json.
}
}
我的测试
namespace Tests\Feature;
use Mockery;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Rules\SomeRule;
class LoansTest extends TestCase
{
use RefreshDatabase;
public function tearDown(): void
{
parent::tearDown();
Mockery::close();
}
/** @test */
public function the_sad_path__when_email_is_invalid()
{
$rule = Mockery::mock(SomeRule::class)->shouldReceive('passes')->once();
$this->app->instance(SomeRule::class, $rule);
$response = $this->json('POST', '/api/loans', ['email' => '[email protected]']);
}
}
我考虑了在 AppServiceProvider 中注册 SomeRule 的想法。但这仍然没有起到任何作用:
public function register()
{
$this->app->bind(SomeRule::class, function ($app) {
return new SomeRule();
});
}
代码在Github
解决此问题的一种方法是更新控制器以将
SomeRule
的分辨率推迟到容器:
public function store(Request $request, Application $app)
{
$request->validate([
'email' => ['required', $app->make(SomeRule::class)]
]);
}
这样,当我们在测试中将模拟对象绑定到
SomeRule::class
时,容器就有机会解析模拟对象而不是具体实例。
您可以通过直接在控制器方法上键入提示
SomeRule
来进一步简化这一步骤:
public function store(Request $request, SomeRule $someRule)
{
$request->validate([
'email' => ['required', $someRule]
]);
}
对于那些使用较新版本的 Laravel 的人来说,使用一些语法糖创建模拟并将其绑定到容器现在变得更加简单:
/** @test */
public function the_sad_path__when_email_is_invalid()
{
$this->mock(SomeRule::class)->expects('passes');
// ...
}
你需要这样使用
class LoanController extends Controller
{
public function store(Request $request)
{
$request->validate([
'email' => ['required', new SomeRule()]
]);
// ...insert in database, return json.
}
}