Есть ли способ действовать как пользователь внутри Laravel, не затрагивая базу данных? - PullRequest
0 голосов
/ 05 июня 2019

Я пишу модульные тесты для API с использованием PHPUnit и Laravel.Большинство тестируемых функций требуют, чтобы пользователь прошел аутентификацию, прежде чем функция будет запущена.Пользовательские данные хранятся в одной таблице, а их разрешения хранятся в другой таблице.Я могу подделать пользовательский объект внутри Laravel, но мне нужно иметь возможность также извлекать соответствующие разрешения из другой таблицы, не обращаясь к базе данных, как это делает маршрутизатор dingo.

В настоящее время работает Laravel 5.8и PHPUnit 8.1.5.В настоящее время у меня есть объект пользователей, сгенерированный на фабрике Laravel, который был сохранен в текстовом файле.Я могу передать это в функцию с именем «actAsApi» (находится на Github, код ниже), и это позволяет мне аутентифицироваться как этот пользователь.Тем не менее, функция по-прежнему выходит и получает все разрешения для этого пользователя из базы данных.Я пытаюсь смоделировать или подделать объект прав доступа, который он куда-то извлекает, чтобы ему вообще не нужно было попадать в базу данных.Я также попытался использовать встроенные функции Passport для Passport :: actAs , и они тоже не работали, так как все еще ударяли по БД (и в действительности не работали в любом случае).

actAsApi (внутри TestCase.php)

protected function actingAsApi($user)
    {
        // mock service middleware
        $auth = Mockery::mock('Dingo\Api\Http\Middleware\Auth[handle]',
            [
                Mockery::mock('Dingo\Api\Routing\Router'),
                Mockery::mock('Dingo\Api\Auth\Auth'),
            ]);
        $auth->shouldReceive('handle')
            ->andReturnUsing(function ($request, \Closure $next) {
                return $next($request);
            });
        $this->app->instance('Dingo\Api\Http\Middleware\Auth', $auth);
        $auth = Mockery::mock('Dingo\Api\Auth\Auth[user]',
            [
                app('Dingo\Api\Routing\Router'),
                app('Illuminate\Container\Container'),
                [],
            ]);
        $auth->shouldReceive('user')
            ->andReturnUsing(function () use ($user) {
                return $user;
            });
        $this->app->instance('Dingo\Api\Auth\Auth', $auth);
        return $this;
    }

Тест внутри моего файла теста

public function testActAs() {
    $user = 'tests/users/user1.txt';
    $this->actingAsApi($user);

    $request = new Request;
    $t = new TestController($request);

    $test = $t->index($request);
}

Я ожидаю, что функция actAsApi позволит мне также передавать ложные данные разрешений, которые соответствуют моемуимитировать данные объекта пользователя из файла, но вместо этого он нажимает на базу данных для извлечения из таблицы разрешений.

РЕДАКТИРОВАТЬ:

Так что я поигрался с созданием фиктивных объектов, и яразобрался, как смоделировать оригинальный контроллер здесь:

$controlMock = Mockery::mock('App\Http\Controllers\Controller', [$request])->makePartial();

$controlMock->shouldReceive('userHasPermission')
            ->with('API_ACCESS')
            ->andReturn(true);

$this->app->instance('App\Http\Controllers\Controller', $controlMock);

, но теперь я не могу понять, как получить мой вызов от других контроллеров, чтобы поразить имитированный контроллер, а не реальный.Вот мой код для запуска примера контроллера:

$info = $this->app->make('App\API\Controllers\InfoController');

print_r($info->getInfo('12345'));

Как я могу сделать так, чтобы второй блок кода попадал на смоделированный контроллер и не выдерживал реальный, как это происходит в методе конструктора?

1 Ответ

1 голос
/ 07 июня 2019

Наконец пришел ответ, и теперь он исправлен.Вот как я это сделал для тех, кто интересуется:

$request = new Request;

$controlMock = m::mock('App\API\Controllers\InfoController', [$request])->makePartial();
$controlMock->shouldReceive('userHasPermission')
             ->with('API_ACCESS')
             ->andReturn(true);

print_r($controlMock->getInfo('12345'));

По сути, я пытался издеваться над оригинальным контроллером API, а затем перехватывать все вызовы.Вместо этого я должен был издеваться над контроллером, который я тестирую, в данном случае InfoController.Затем я могу перехватить вызов userHasPermission, который должен обратиться к контроллеру, но я автоматически возвращаю true.Это исключает необходимость попадания в базу данных для получения разрешений и другой информации.Более подробную информацию о том, как я решил это с помощью Mockery, можно найти здесь: http://docs.mockery.io/en/latest/cookbook/big_parent_class.html. Как видите, это называется «Большой родительский класс».Удачи!

...