如何模拟Laravel Auth外观的给定方法

问题描述

我想测试调用createuserProivder()方法时的Auth外观是否返回我的用户提供程序。

问题在于,使用以下代码以及注释掉的部分,AuthManager仍然是原始版本,而不是模拟版本。 对于未注释的部分,我得到一个错误Mockery\Exception\BadMethodCallException : Method Mockery_2_Illuminate_Auth_AuthManager::validate() does not exist on this mock object

我不知道如何测试。

我想测试一种自定义防护行为,该行为在调用Guard的validated()方法调用UserProvider,因此,我需要模拟Auth外观,因为它是返回User Provider的外观。

public function testUserIsAuthenticatedWhenUserProviderFindsCredentialsmatch()
    {
        $userId = Uuid::uuid();
        $user = new User($userId);
        $userProvider = new UserProvider($user);

//        $this->partialMock(AuthManager::class,function ($mock) use ($userProvider) {
//            $mock->shouldReceive('createuserProvider')
//                ->once()
//                ->andReturn($userProvider);
//        });

        Auth::shouldReceive('createuserProvider')
           ->once()
           ->andReturn($userProvider);

        $result = $this->app['auth']->validate(['dummy' => 123]);

测试方法

/**
     * @param array $credentials
     * @return bool
     */
    public function validate(array $credentials = []): bool
    {
        $this->user = $this->provider->retrieveByCredentials($credentials);

        return (bool)$this->user;
    }

服务提供商:

class LaravelServiceProvider extends AuthServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        Auth::extend(
            'jwt',function ($app,$name,array $config) {
                $moduleConfig = $app['config'];

                return new JWTAuthGuard(
                    Auth::createuserProvider($config['provider']),$this->app['request'],new JWTHelper()
                );
            }
        );
    }
}

解决方法

仅仅是因为您创建了模拟类,并不意味着它会在服务容器中自动替换。身份验证管理器绑定为单例,因此您可以使用以下命令更新服务容器中的共享实例:

$mock = $this->partialMock(AuthManager::class,function ($mock) use ($userProvider) {
            $mock->shouldReceive('createUserProvider')
                ->once()
                ->andReturn($userProvider);
        });

$this->app->instance('auth',$mock);

$result = $this->app['auth']->validate(['dummy' => 123]);

...
,

经过大量调试后,我发现了可以执行此操作的地方:

ALT_MSG_MAP

不过,另一种方法是只在Tests目录中创建一个UserProvider进行测试:

protected function getEnvironmentSetUp($app)
{
    $this->mockUserProvider($app);
}

protected function mockUserProvider($app)

{
    $userId = Uuid::uuid();
    $user = new User($userId);
    $userProvider = new UserProvider($user);

    $mock = Mockery::mock(AuthManager::class)->makePartial();
    $reflection = new ReflectionClass($mock);
    $reflection_property = $reflection->getProperty('app');
    $reflection_property->setAccessible(true);
    $reflection_property->setValue($mock,$app);

    $mock
        ->shouldReceive('createUserProvider')
        ->andReturn($userProvider);
    $app->instance('auth',$mock);
}

然后在测试文件中

class TestUserProvider extends AuthServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Auth::provider(
            'TestProvider',function ($app,array $config) {
                return new UserProvider();
            }
        );
    }
}