Symfony 功能测试和会话持久性

Posted

技术标签:

【中文标题】Symfony 功能测试和会话持久性【英文标题】:Symfony2 functional test and session persistance 【发布时间】:2016-07-26 12:41:05 【问题描述】:

这是我的问题,我从功能测试控制器添加会话变量,并且它们不会弹出测试目标的操​​作。

我做了一个登录方法,使用cookbook advice登录。我稍微调整了一下,允许2个帐户登录:admin和superadmin

/**
     * @param $account string the account to log in with (authorized : superadmin and admin)
     */
    protected function logIn($account)
    
        $this->session = $this->container->get('session');
        // Cookbook try
        // $this->session = new Session(new MockFileSessionStorage());
        $user = $this->em->getRepository('LCHUserBundle:User')->findOneByUsername($account);
        $firewall = 'admin_area';

        switch($account) 
            case self::SUPER_ADMIN_LOGIN:
                $token = new UsernamePasswordToken($user, $account, $firewall, array('ROLE_SUPER_ADMIN'));
                $this->client->setServerParameter("SERVER_NAME", SiteControllerTest::ROOT_SITE);
                $this->client->setServerParameter("HTTP_HOST", SiteControllerTest::ROOT_SITE);
                break;
            case self::ADMIN_LOGIN:
                $token = new UsernamePasswordToken($user, $account, $firewall, array('ROLE_ADMIN'));

                // Session var I wish to have on my controller action tested
                $this->session->set('currentSite', $this->em->getRepository('LCHMultisiteBundle:Site')->find(1));
                $this->session->save();

                // Use to force server canonical name for admin test
                $this->client->setServerParameter("SERVER_NAME", SiteControllerTest::ROOT_SITE);
                $this->client->setServerParameter("HTTP_HOST", SiteControllerTest::TEST_SITE);
                break;
            default:
                throw new UsernameNotFoundException('Username provided doesn\'t match any authorized account');
        
        // Save user in session
        $this->session->set('_security_'.$firewall, serialize($token));
        $this->session->set('user', $user);
        $this->session->save();
        // $this->container->set('session', $this->session);

        $cookie = new Cookie($this->session->getName(), $this->session->getId());
        $this->client->getCookieJar()->set($cookie);

我的 setUp() 方法是这样做的:

/**
     * @inheritDoc
     */
    protected function setUp()
    
        // Initiates client
        $this->client = static::createClient();

        $this->container = $this->client->getContainer();
        $this->application = new Application($this->client->getKernel());
        $this->application->setAutoExit(false);
        $this->translator = $this->container->get('translator');
        $this->em = $this->container
            ->get('doctrine')
            ->getManager();
    

您可以看到我为身份验证设置了会话变量。当我从测试操作中转储会话变量时,它们会正确显示,但如果我添加我的 currentSite 会话变量,它似乎不会持续存在。由于我使用客户端提供的测试容器,它应该被传递不是吗?

PS:根据this other question,我还覆盖了客户端类。

我发现了许多关于该主题的帖子,但没有一个提供任何可行的解决方案(this one、this one 或 that one)。 我还发现了这个cookbook article。

更新:感谢 Alex Blex 的评论,我在这里澄清了我的一些问题。

setUp() 和 logIn() 都是自定义 WebTestCase 类的一部分,嵌入了我的应用程序特性所需的工具(例如翻译器...) 我的主要观点是在测试控制器中设置会话参数并在测试操作中检索这些会话参数

【问题讨论】:

【参考方案1】:

目前还不清楚您正在测试什么、您的期望是什么以及失败的地方。添加实际测试是有意义的。为什么你的测试中需要容器、翻译器等?

会话没有什么特别需要做的。考虑这个示例控制器,它在会话中保持 'test' 的值并在连续调用时增加它:

/**
 * @Route("/session")
 * @Method("GET")
 */
public function session()

    $session = $this->container->get('session');
    $current = $session->get('test', 0);
    $session->set('test', $current + 1);
    return new Response($current);

这个测试通过了:

/**
 * @test
 */
public function session_increments()

    $client = static::createClient();        
    $client->request("GET", '/session');
    $this->assertEquals('0', $client->getResponse()->getContent());
    $client->request("GET", '/session');
    $this->assertEquals('1', $client->getResponse()->getContent());

您的应用程序逻辑可能要复杂得多,但测试应该保持几乎相同 - 第一次调用登录,第二次调用断言响应包含登录用户独有的内容。

更新

应尽可能避免在功能测试中使用内部实现,但对于某些边缘情况可能是必不可少的,例如简化测试场景。

以下示例通过在测试场景中为会话变量设置特定值来测试同一个控制器,并检查应用返回的值:

/**
 * @test
 */
public function session_returns_value()

    $client = static::createClient();        
    $session = $client->getContainer()->get('session');
    $session->set('test', 12);
    $client->request("GET", '/session');
    $this->assertEquals('12', $client->getResponse()->getContent());

【讨论】:

感谢您的回复。我会澄清我的问题。我的帖子的重点是找出为什么测试控制器中的会话变量初始化在测试操作中消失了。我还找到了一个我会尽快发布的解决方案。 很公平,我已经更新了答案。仍然不相信您需要所有这些设置混乱。

以上是关于Symfony 功能测试和会话持久性的主要内容,如果未能解决你的问题,请参考以下文章

通过 AJAX 调用创建后 Symfony 2 会话不持久

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

在会话中存储对象 Symfony 2

Symfony:以JSON存储会话

护照登录和持久会话

如何通过伪造登录来测试 Symfony 2 中的 ACL