单元测试 Symfony2

Posted

技术标签:

【中文标题】单元测试 Symfony2【英文标题】:Unit Test Symfony2 【发布时间】:2012-11-27 19:13:17 【问题描述】:

我正在尝试使用 Mockery 来对我的 sf2 函数进行单元测试。 我的第一次尝试很艰难。

首先尝试测试一个使用安全上下文的类:

public function setSecurityContext(SecurityContext $securityContext)

    $this->securityContext = $securityContext;
    try 
        $this->isLoggedIn = $securityContext->isGranted('IS_AUTHENTICATED_FULLY');
        $this->user = $securityContext->getToken()->getUser();
     catch (\Exception $e) 
        $this->isLoggedIn = false;
        $this->user = $securityContext->getToken()->getUser();
    

我创建了一个 testsetSecurityContext 函数,如下所示:

public function testsetSecurityContext()

    /* @var $securityContext SecurityContext */
    $securityContext = m::mock('Symfony\Component\Security\Core\SecurityContext');

    $securityContext->shouldReceive('isGranted')
    ->with('IS_AUTHENTICATED_FULLY')
    ->once()
    ->andReturn(true);

    $factory = m::mock('Knp\Menu\FactoryInterface');

    $menu = new MenuBuilder($factory);

    $menu->setSecurityContext($securityContext);

运行单元测试时,我收到错误:

testsetSecurityContext

Mockery\Exception:方法 isGranted 被标记为 final,并且无法生成定义了此类方法的模拟对象。您应该将此对象的实例传递给 Mockery 以创建部分模拟。

所以我相应地改变了我的测试功能:

public function testsetSecurityContext()

    /* @var $securityContext SecurityContext */
    $securityContext = m::mock(new \Symfony\Component\Security\Core\SecurityContext());
    /* ... skipped ... */

现在我收到了这个错误:

testsetSecurityContext

ErrorException: 可捕获的致命错误:参数 1 传递给 Symfony\Component\Security\Core\SecurityContext::__construct() 必须实现接口 Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface,无给定,在第 91 行的 ..MenuBuilderTest.php 中调用并在 ..Symfony\Component\Security\Core\SecurityContext.php 第 41 行定义

所以我再次修改我的代码:

public function testsetSecurityContext()


    $auth = m::mock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');

    /* @var $securityContext SecurityContext */
    $securityContext = m::mock(new \Symfony\Component\Security\Core\SecurityContext($auth));

    /* ... skipped ... */


我得到另一个错误:

testsetSecurityContext

ErrorException: 可捕获的致命错误:参数 2 传递给 Symfony\Component\Security\Core\SecurityContext::__construct() 必须实现接口 Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface,无给定,在第 94 行的 ...\MenuBuilderTest.php 中调用并在 ...\Symfony\Component\Security\Core\SecurityContext.php 第 41 行定义

我最终得到:

public function testsetSecurityContext()


    $am = m::mock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
    $adm = m::mock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');

    /* @var $securityContext SecurityContext */
    $securityContext = m::mock(new \Symfony\Component\Security\Core\SecurityContext($am, $adm));

    $securityContext->shouldReceive('isGranted')
    ->with('IS_AUTHENTICATED_FULLY')
    ->once()
    ->andReturn(true);

    $factory = m::mock('Knp\Menu\FactoryInterface');

    $menu = new MenuBuilder($factory);

    $menu->setSecurityContext($securityContext);

这仍然不行,因为我得到了那个错误:

testsetSecurityContext

ErrorException:可捕获的致命错误:参数 1 传递给 Atos\Worldline\Fm\Integration\Ucs\EventFlowAnalyser\Menu\MenuBuilder::setSecurityContext() 必须是 Symfony\Component\Security\Core\SecurityContext 的实例,给出了 Mockery_50c5c1e0e68d2 的实例,在第 106 行的 ..\MenuBuilderTest.php 中调用并在 ..\MenuBuilder.php 第 140 行定义

在我最终完成 100 行测试以测试 8 行功能之前,我真的很感激一些帮助...

【问题讨论】:

【参考方案1】:

不要模拟实例,而是选择它实现的接口。它几乎总是工作得更好,而且 Symfony2 中的几乎所有东西都有明确定义的接口。

如果 MenuBuilder 是自定义类,它也应该使用接口而不是实际实现。

Symfony\Component\Security\Core\SecurityContextInterface

public function testsetSecurityContext()

    /* @var $securityContext SecurityContext */
    $securityContext = m::mock('Symfony\Component\Security\Core\SecurityContextInterface');

    $securityContext->shouldReceive('isGranted')
    ->with('IS_AUTHENTICATED_FULLY')
    ->once()
    ->andReturn(true);

    $factory = m::mock('Knp\Menu\FactoryInterface');

    $menu = new MenuBuilder($factory);

    $menu->setSecurityContext($securityContext);

【讨论】:

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

通过单元测试访问 Symfony 2 容器?

如何使用 Symfony 2 在单元测试中获取当前登录的用户?

如何在 symfony2 功能测试中发出 https 请求?

MVC Web 应用程序中的控制器应该是可单元测试的吗?

PHPUnit、接口和命名空间 (Symfony2)

简单的控制器功能测试失败