Symfony 3.4 功能测试

Posted

技术标签:

【中文标题】Symfony 3.4 功能测试【英文标题】:Symfony 3.4 Functional tests 【发布时间】:2021-02-06 10:19:48 【问题描述】:

我在使用 symfony 3.4 进行功能测试时遇到了一个错误。

我的应用运行自定义 GuardAuthenticator 以在 CAS 身份验证中对我的用户进行身份验证。这只是为了解释上下文。在我的测试中,我不想使用它,我想使用特定的身份验证系统。

我编写了功能测试。我使用以下内容开始了我的测试环境:

# app/config/config_test.yml
imports:
    -  resource: config_dev.yml 

framework:
    test: ~
    session:
        storage_id: session.storage.mock_file
        name: MOCKSESSION
    profiler:
        collect: false

根据官方 Symfony 文档,我扩展了 symfony WebTestCase 为我的测试设置一个特定的身份验证令牌How to Simulate HTTP Authentication in a Functional Test

namespace Test\AppBunble\WebTestCase;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as SfTestCase;

class WebTestCase extends SfTestCase

    /**
     *
     * @inheritDoc
     * @see \phpUnit_Framework_TestCase::setUp()
     */
    public function setUp()
    
        $this->client = static::createClient();
        $this->container = $this->client->getContainer();
        $this->entityManager = $this->container->get('doctrine.orm.entity_manager');

        parent::setUp();
    

    public function logInAs($username)
    
        $user = $this->entityManager->getRepository(User::class)->loadUserByUsername($username);
        
        $session = $this->client->getContainer()->get('session');
        $token = new PostAuthenticationGuardToken($user, 'main', $user->getRoles());
        $session->set('_security_main', serialize($token));
        
        $session->save();
        
        $cookie = new Cookie($session->getName(), $session->getId());
        $this->client->getCookieJar()->set($cookie);
    


最后,我写了我的(简单)测试:

namespace Tests\AppBundle\Controller;

use Tests\AppBundle\WebTestCase;

class DefaultControllerTest extends WebTestCase

    public function testIndex()
    
        $this->logInAs('admin');
        $crawler = $this->client->request('GET', '/');
        $this->assertTrue($client->getResponse()->isSuccessful(), 'response status is 2xx');
    

我跑了 phpunit:

$ ./vendor/bin/simple-phpunit 
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

Testing app Test Suite
<br />
<b>Error</b>: <font color="FF0000"><b>Internal script failure</b><br />

为了调试,我修改了我的测试:

    public function testIndex()
    
        $this->logInAs('admin');
        //$crawler = $this->client->request('GET', '/');
        //$this->assertTrue($client->getResponse()->isSuccessful(), 'response status is 2xx');
    

我跑了 phpunit:

 ./vendor/bin/simple-phpunit 
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

Testing app Test Suite
.                                                                   1 / 1 (100%)

Time: 797 ms, Memory: 27.75MB

OK (1 test, 0 assertions)

经过大量测试后,我在调用测试时发现:

$this->client->request('GET', '/')

它崩溃了。

更新:另一个测试。

如果我运行这个:

    public function testIndex()
    
        $this->logInAs('admin');
        $token = $this->client->getContainer()->get('security.token_storage');
        var_dump($token->getToken());

        //$crawler = $this->client->request('GET', '/');
        //$this->assertTrue($client->getResponse()->isSuccessful(), 'response status is 2xx');
    

它返回给我NULL...没有令牌。

更新 2

我深入研究代码以回到 symfony 停止的地方。它在Symfony\Component\EventDispatcher\EventDispatcher 类的doDispatch 方法中。

它触发 `kernel.event' 事件的监听器。而当它触发名为“Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener”=>“内部脚本失败”的监听器时。

更新 3 如果我比较 dev.log(代表我在浏览器中运行应用程序时的日志),我会在请求中获得此日志:

[2020-10-23 13:55:56] request.INFO: Matched route "app_homepage". "route":"app_homepage","route_parameters":"_controller":"AppBundle\\Controller\\DefaultController::indexAction","_route":"app_homepage","request_uri":"http://localhost:8180/","method":"GET" []
[2020-10-23 13:55:56] security.DEBUG: Read existing security token from the session. "key":"_security_main","token_class":"Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken" []
[2020-10-23 13:55:56] doctrine.DEBUG: SELECT [...]
[2020-10-23 13:55:56] security.DEBUG: User was reloaded from a user provider.  [...]

但是当我运行 $this-&gt;client-&gt;request('GET', '/') 时,我的 test.log 显示:

[2020-10-23 13:55:56] request.INFO: Matched route "app_homepage". "route":"app_homepage","route_parameters":"_controller":"AppBundle\\Controller\\DefaultController::indexAction","_route":"app_homepage","request_uri":"http://localhost","method":"GET" []

没有来自安全的痕迹。

更新 4:另一个测试

我运行了这个测试:

    public function testIndex()
    
        $crawler = $this->client->request('GET', '/stackTest');
        $this->assertTrue($this->client->getResponse()->isSuccessful(), 'response status is 2xx');
    

在security.yml中有这个配置的页面

firewalls:
    stack:
        pattern: ^/stackTest
        security: false

...测试成功了!

 ./vendor/bin/simple-phpunit 
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

Testing app Test Suite
.                                                                   1 / 1 (100%)

Time: 1.08 seconds, Memory: 36.50MB

OK (1 test, 1 assertion)

【问题讨论】:

也许你需要实现这部分文档中提到的接口 Serializable 和 EquatableInterface ? symfony.com/doc/current/security/… @Vyctorya,My User 实体实现了 Serializable 接口。当我观看 test.log 时,当我调用 $this-&gt;client-&gt;request('GET', '/') 时,唯一的一行是 [2020-10-23 13:21:01] request.INFO: Matched route "app_homepage". "route":"app_homepage","route_parameters":"_controller":"AppBundle\\Controller\\DefaultController::indexAction","_route":"app_homepage","request_uri":"http://localhost/","method":"GET" []。好像 symfony 在某处停止,这很奇怪,因此出现“内部服务器错误”消息。 当您实现\Serializable 时,可能不是所有必要的属性都正确序列化/反序列化,用于比较用户是否更改。尝试调试Symfony\Component\Security\Core\Authentication\Token\AbstractToken::hasUserChanged()。但这很奇怪,它因错误而失败,我猜是其他地方的问题。 @vstelmakh,未达到 hasUserChanged 方法。我认为“内部脚本失败”之前停止了该过程。也许,我对功能测试的身份验证做错了什么?我迷路了......我认为问题出在其他地方 【参考方案1】:

我找到了!

如上所述,我的应用程序的身份验证是通过 CAS 完成的。为了测试,我想模拟这种身份验证。所以我创建了一个 FakeGuardAuthenticator,它不是询问 CAS 服务器,而是模拟它并返回凭据。

因此,在我的 config_test.yml 配置文件中,我必须通过别名来覆盖 guardAuthenticator。

哪个给:

# app/config/config_test.yml
imports:
    -  resource: config_dev.yml 
    -  resource: services_test.yml 
# app/config/service_test.yml
services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    app_cas.guard_authenticator:
        class : Tests\AppBundle\FakeGuardAuthenticator
        arguments:
          # [...]
        provider: cas

感谢@vstelmakh 和@Vyctorya 花时间回复我。

【讨论】:

很高兴知道您找到了解决方案。不要忘记接受你自己的答案。这可以帮助其他人知道问题已解决。 ***.blog/2009/01/06/accept-your-own-answers

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

Hwi oauth bundle 和 Symfony 3.4 无法自动装配服务:如何在 symfony 3.4 + FOSUserBundle 中使用 hwi/oauth-bundle

symfony 3.4 设置 prod 环境

Symfony LTS:如何从 2.8 升级到 3.4?

Symfony 3.4 安装期间的错误 php json

无法自动装配服务 FOSUserBundle,Symfony 3.4

从 Symfony 3.4 升级到 4:升级 symfony 时出错