2

我们有以下中间件。我们知道中间件可以正常工作,因为在浏览器中测试应用程序正常工作。可悲的是,在编写 HTTP 测试用例时,刀片说中间件定义的变量不存在。

<?php

namespace App\Http\Middleware;

use App\Repository\UserContract;
use Closure;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Support\Facades\View;

class Authenticate
{
    private $userRepository;
    private $view;

    public function __construct(UserContract $userRepository, ViewFactory $view)
    {
        $this->userRepository = $userRepository;
        $this->view = $view;
    }

    public function handle($request, Closure $next)
    {
        $userId = null;
        $username = null;
        if ($request->hasCookie('auth')) {
            $secret = $request->cookie('auth');
            $userId = $this->userRepository->getUserIdBySecret($secret);
            $username = $this->userRepository->getUsername($userId);
        }
        $this->view->share('username', $username);
        $request['_user_id'] = $userId;
        $request['_username'] = $username;
        return $next($request);
    }
}

我们进行如下 PHPUnit 测试:

    /**
     * @test
     */
    public function it_shows_logged_in_username()
    {
        $app = $this->createApplication();
        $encrypter = $app->get(Encrypter::class);
        $userRepository = $app->make(UserContract::class);
        $userRepository->addUser('jane', 'secret');

        $secret = $encrypter->encrypt('secret', false);
        $response = $this->call('GET', '/', [], ['auth' => $secret], [], [], null);
        $response->assertSeeText('jane');
    }

错误

ErrorException {#980                                                                                                                                           
  #message: "Undefined variable: username"                                                                                                                     
  #code: 0                                                                                                                                                     
  #file: "./storage/framework/views/db4b9232a3b0957f912084f26d9041e8a510bd6c.php"
  #line: 3                                                                     
  #severity: E_NOTICE                                                          
  trace: {                                                                     
    ./storage/framework/views/db4b9232a3b0957f912084f26d9041e8a510bd6c.php:3 {
      › <?php dump($comments); ?>                                              
      › <?php dump($username); ?>  

任何意见,将不胜感激?

编辑

我必须使用View外观添加它并调用它的share方法使其工作,但我遇到了errors应该由\Illuminate\View\Middleware\ShareErrorsFromSession股票 laravel 中间件设置的变量的相同问题。

其他备注,我的中间件被调用Authenticate,但它与 Laravel 的基于密码的普通身份验证无关。

这里UserContract

<?php
declare(strict_types=1);


namespace App\Repository;


use App\Repository\Exception\UserAlreadyRegisteredException;

interface UserContract
{
    public function isRegistered(string $username): bool;

    public function getUserID(string $username): int;

    public function getUserIdBySecret(string $secret): int;

    /**
     * @param int $userId
     *
     * @return string
     * @throws
     */
    public function getUsername(int $userId): string;

    /**
     * @param int $userId
     *
     * @return string
     * @throws AuthSecretNotSetException
     */
    public function getUserAuthSecret(int $userId): string;

    public function getNextId(): int;

    /**
     * @param string $username
     * @param string $authSecret
     *
     * @return int
     * @throws UserAlreadyRegisteredException
     */
    public function addUser(string $username, string $authSecret): int;

    public function fetchUpdatedBetween(?\DateTimeInterface $start, ?\DateTimeInterface $end): array;

    public function markAsSynced(int $userId): void;

    public function isSynced(int $userId): bool;

    public function delete(int $userId): void;

    public function markAsDeleted(int $userId): void;

    public function fetchDeletedIds(): array;

    public function removeDeletedFlag(int $userId): void;

    public function fetchStalledIds(\DateTimeInterface $dateTime): array;

    public function purge(int $userId): void;

    /**
     * @param UserFetcherContract $fetcher the closure would be passed userId and it should return data or null
     */
    public function setFallbackFetcher(UserFetcherContract $fetcher): void;
}
4

3 回答 3

2

要正确测试登录,您应该提交一个发布请求,因此更改:

$response = $this->call('GET', '/', [], ['auth' => $secret], [], [], null);

$response = $this->call('POST', '/', [], ['auth' => $secret], [], [], null);




或者,如果您只想测试视图而不是登录表单本身,您可以使用该actingAs方法...

创建时在变量中捕获用户:

$user = $userRepository->addUser('jane', 'secret');

使用该actingAs方法以登录方式测试视图$user

$this->actingAs($user)->get('/')->assertSeeText('jane');;
于 2019-09-13T16:05:30.403 回答
1

尝试view()->share('username', $username)

于 2019-09-12T21:25:23.850 回答
1

我终于花时间对此进行了深入研究。

事实证明问题正在发生,因为我正在创建已启动应用程序的多个实例,并且它以某种方式与应用程序中注册的视图工厂的实例混淆。

在测试用例中删除此行使其工作:

/**
     * @test
     */
    public function it_shows_logged_in_username()
    {
        // THIS IS WRONG
        // $app = $this->createApplication();
        $app = $this->app; // Use application instantiated in setUp method of test case
        $encrypter = $app->get(Encrypter::class);
        $userRepository = $app->make(UserContract::class);
        $userRepository->addUser('jane', 'secret');

        $secret = $encrypter->encrypt('secret', false);
        $response = $this->call('GET', '/', [], ['auth' => $secret], [], [], null);
        $response->assertSeeText('jane');
    }

我不是 100% 确定为什么启动应用程序的多个实例会产生问题,但我的直觉是:某处的一些共享数据......

对于任何对这里感兴趣的人,提交

于 2019-09-29T02:01:42.777 回答