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

时间:2017-12-19 07:39:02

标签: symfony unit-testing authentication doctrine

在带有Doctrine的Symfony 3中,我试图让#34;最后更新为"数据库中的列,只要将更改保存到表中,该列就会自动设置为登录用户的用户名。

我正在使用EventSubscriber执行此操作,当我将系统用于实际时,该功能正常运行,但是当我运行单元测试时,它认为没有用户登录。

我按照how to implement authentication for unit tests上的说明提出了两种方法 - 使用Basic auth或设置令牌。这两种方法都允许测试运行,就像用户经过身份验证一样,但是它们都不允许我检索登录用户的用户名,所以我无法测试"最后更新的" ;正确设置了列。

我做错了什么?还有其他方法我应该在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
AppBundle\EventListener\BaseEntitySubscriber:
    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']);
}

1 个答案:

答案 0 :(得分:1)

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

$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用户