drema2014 2012-12-10 11:13
浏览 76
已采纳

单元测试Symfony2

I am trying to use Mockery in order to unit test my sf2 functions. I am strugeling with my first attempt.

First try at test a class which uses security context:

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();
    }
}

I create a testsetSecurityContext function like this:

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);
}

When running unit test, I receive the error:

testsetSecurityContext

Mockery\Exception: The method isGranted is marked final and it is not possible to generate a mock object with such a method defined. You should instead pass an instance of this object to Mockery to create a partial mock.

So I change my test function accordingly:

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

Now I receive that error:

testsetSecurityContext

ErrorException: Catchable Fatal Error: Argument 1 passed to Symfony\Component\Security\Core\SecurityContext::__construct() must implement interface Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface, none given, called in ..MenuBuilderTest.php on line 91 and defined in ..Symfony\Component\Security\Core\SecurityContext.php line 41

So I modify my code again:

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 ... */

}

And I get another error:

testsetSecurityContext

ErrorException: Catchable Fatal Error: Argument 2 passed to Symfony\Component\Security\Core\SecurityContext::__construct() must implement interface Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface, none given, called in ...\MenuBuilderTest.php on line 94 and defined in ...\Symfony\Component\Security\Core\SecurityContext.php line 41

I endup with:

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);
}

And that is still not OK as I get that error:

testsetSecurityContext

ErrorException: Catchable Fatal Error: Argument 1 passed to Atos\Worldline\Fm\Integration\Ucs\EventFlowAnalyser\Menu\MenuBuilder::setSecurityContext() must be an instance of Symfony\Component\Security\Core\SecurityContext, instance of Mockery_50c5c1e0e68d2 given, called in ..\MenuBuilderTest.php on line 106 and defined in ..\MenuBuilder.php line 140

I really would appreciate some help before I end-up with 100 lines test to test a 8 lines function...

  • 写回答

1条回答 默认 最新

  • dongqucheng3851 2012-12-10 14:29
    关注

    Instead of mocking the instance, go for the interface it implements. It almost always works better and nearly everything in Symfony2 has well defined interfaces.

    If MenuBuilder is a custom class, it should use the interface too rather than the actual implementation.

    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);
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 pip2.40更新pip2.43时报错
  • ¥15 换yum源但仍然用不了httpd
  • ¥50 C# 使用DEVMOD设置打印机首选项
  • ¥15 麒麟V10 arm安装gdal
  • ¥15 想用@vueuse 把项目动态改成深色主题,localStorge里面的vueuse-color-scheme一开始就给我改成了dark,不知道什么原因(相关搜索:背景颜色)
  • ¥20 OPENVPN连接问题
  • ¥15 flask实现搜索框访问数据库
  • ¥15 mrk3399刷完安卓11后投屏调试只能显示一个设备
  • ¥100 如何用js写一个游戏云存档
  • ¥15 ansys fluent计算闪退