Тест Laravel проходит промежуточное программное обеспечение аутентификации, но не работает Auth::user() с поставщиками данных

Я тестирую свое приложение Laravel с интегрированной конфигурацией PHPUnit, и у меня возникают проблемы с аутентификацией пользователя внутри теста.

У меня есть этот тест (сокращенный)

public function testShowEditForm($user, $expectedStatus, $expectedLocation, $expectedSee, $expectedDontSee) {
    if ($user !== null)
        $this->actingAs($user);

    // $this->assertAuthenticatedAs($user); -> This is true!

    $response = $this->get("/objects/edit/");

    $response->assertStatus($expectedStatus);

    // [...]
}

с этим поставщиком данных:

public function showEditFormProvider() {
    return [
        'allowedUser' => [
            UserGenerator::getControllingUser(),
            200,
            null,
            ["something"],
            []
        ]
    ];
}

UserGenerator::getControllingUser() просто запускает фабрику пользователей, добавляет некоторые права и возвращает объект пользователя.

Проверенный метод (также сокращенный):

public function edit($object_id = null) {
    $user = User::find(Auth::user()->id); // Auth::user() returns null
    // [...]
}

Маршрут для этого метода инкапсулирован внутри части "middleware" => "auth" в файле route/web.php.

Проблема: поставщик данных вызывается правильно, он проходит промежуточное ПО, но вызов Auth::user() в методе edit() возвращает null, так что аутентификация все равно не удалась, несмотря на прохождение промежуточное ПО?

  • Если я заменю параметр $user в testShowEditForm непосредственно на UserGenerator::getControllingUser(), это сработает (но это не очень хороший обходной путь, потому что у меня много тестовых случаев, и поэтому мне нужны поставщики данных).
  • Поэтому я работал, вызывая поставщик данных с помощью $this->showEditFormProvider() в первой строке тестового метода testShowEditForm(), но он вызывается дважды (каково правильное поведение в соответствии с этим 1). Но это также не идеальный обходной путь, потому что, если я создаю объект в провайдере для тестирования, он также создается дважды, и поэтому утверждения терпят неудачу.

Есть ли что-то, что я делаю неправильно? Я уже много искал эту тему, и методы actingAs()/be() в методе тестирования кажутся лучшей практикой для имитации вошедшего в систему пользователя.

1 "Все поставщики данных выполняются как до вызова статического метода setUpBeforeClass, так и до первого вызова метода setUp". https://phpunit.de/manual/3.7/en/writing-tests-for-phpunit.html


person DSharp    schedule 23.09.2019    source источник
comment
Auth::shouldReceive('user')-›andReturn($user); это тип насмешки, но я обычно использую его в модульном тестировании, а не в функциональном тестировании. Вы также можете попробовать.   -  person mohammad.kaab    schedule 28.12.2019


Ответы (1)


В Laravel 5.8 он работал с использованием

$user = User::find(Auth::id());

вместо

$user = User::find(Auth::user()->id); // Auth::user() returns null

внутри контроллера. Я понятия не имею, почему, но, возможно, это поможет некоторым поисковым разработчикам в будущем. Как ни странно, начиная с Laravel 6 (в настоящее время мое приложение на 6.10.0), больше никаких проблем, даже со «старой» реализацией.

person DSharp    schedule 09.01.2020