在Symfony单元测试期间无法获取用户名

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Symfony单元测试期间无法获取用户名相关的知识,希望对你有一定的参考价值。

在带有Doctrine的Symfony 3中,我试图在数据库中有一个“last updated by”列,只要将更改保存到表中,该列就会自动设置为登录用户的用户名。

我正在使用EventSubscriber执行此操作,当我使用系统进行实际操作时可以正常工作,但是当我运行单元测试时,它认为没有用户登录。

我遵循how to implement authentication for unit tests上的说明,它提出了两种方法 - 使用Basic auth或设置令牌。这两种方法都允许测试运行,就像用户通过身份验证一样,但它们都不允许我检索登录用户的用户名,因此我无法测试是否正确设置了“last updated by”列。

我究竟做错了什么?还有其他方法我应该在EventSubscriber中检索登录用户的用户名吗?

这是我的EventSubscriber实现,它适用于实际请求,但在测试运行时返回空标记:

class BaseEntitySubscriber implements EventSubscriber {
    public function getSubscribedEvents() {
        return array('prePersist');
    }

    public function prePersist(LifecycleEventArgs $args) {
        $em = $args->getEntityManager();
        $token = $this->ts->getToken(); // returns null during tests
        $username = $token ? $token->getUsername() : null;
        if ($username === null) throw new Exception("User is not logged in!");
        $entity = $args->getEntity();
        $entity->setLastUpdateBy($username);
    }
}

# services.yml
AppBundleEventListenerBaseEntitySubscriber:
    tags:
        - { name: doctrine.event_subscriber, connection: default }
    arguments: [ "@security.token_storage" ]

编辑:@dbrumann测试代码如下:(大致)

public function testEditLookup()
{
    $idLookup = $this->getFixtureId('lookup.example');

    // Get the existing one first so we know if it changes later.
    $crawler = $this->client->request('GET', "/lookup/$idLookup");
    $lookup = $this->decodeSymfonyJSON($this->client->getResponse());

    $this->assertEquals('Old title', $lookup['title']);
    $this->assertEquals('system', $lookup['last_update_by']);
    $this->assertEquals('Example', $lookup['detail']);

    // Make the change.
    $crawler = $this->client->request('PATCH',
        "/lookup/$idLookup",
        array('title' => 'New title')
    );
    $this->checkSymfonyError($this->client->getResponse());

    // Retrieve it again to confirm it is now different.
    $crawler = $this->client->request('GET', "/lookup/$idLookup");
    $lookup = $this->decodeSymfonyJSON($this->client->getResponse());

    $this->assertEquals('New title', $lookup['title']);
    $this->assertEquals('testuser', $lookup['last_update_by']);
    // Make sure this hasn't changed.
    $this->assertEquals('Example', $lookup['detail']);
}
答案

我想我已经解决了这个问题。事实证明 - 假设我以正确的方式检索用户 - 您需要自己设置令牌:

$user = 'testuser';
$pass = 'testpass';

$this->client = static::createClient(array(), array(
    'php_AUTH_USER' => $user,
    'PHP_AUTH_PW' => $pass,
    'HTTPS' => true, // Default to HTTPS
));

// Also set a token so the username can be retrieved later
$firewallContext = 'main';
$token = new UsernamePasswordToken($user, $pass, $firewallContext, array('ROLE_ADMIN'));
$ts = $this->client->getContainer()->get('security.token_storage');
$ts->setToken($token);

这是测试用例的setUp()实现。

编辑:进一步测试还有一件事需要注意。加载灯具时使用UsernamePasswordToken,运行测试时使用PHP_AUTH_USER。这意味着您可以将初始数据填充为一个用户,然后让不同的用户运行测试。这样可以确保将“上次更新时间”字段更改为正确的用户名。

如果你像我一样使用Doctrine事件订阅者,那么prePersist钩子将看到UsernamePasswordToken用户,而preUpdate钩子将看到PHP_AUTH_USER用户。

以上是关于在Symfony单元测试期间无法获取用户名的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 2 - 在单元测试期间将会话数据添加到请求对象

Symfony PHPUnit 测试不验证用户

在单元测试期间获取引用项目的路径

如何在 Symfony 中为使用 queryBuilder 构建的 MongoDB 查询编写单元测试

如何在 Django REST Framework 中的单元测试期间登录用户?

在 Symfony2 流式传输期间接受请求