在使用 PHPUnit 模拟 class 时,如何防止调用原始方法?

How do I prevent the original method being called when mocking a class with PHPUnit?

根据我对 PHPUnit 文档的阅读,我希望以下代码创建 AuthorizationChecker class 的模拟,当 isGranted() 时 return false方法被调用。但是,改为调用原始方法。我做错了什么?

    $auth = $this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AuthorizationChecker')
        ->disableOriginalConstructor()
        ->setMethods(['isGranted'])
        ->getMock();
    $auth->expects($this->any())
        ->method('isGranted')
        ->with($this->anything())
        ->will($this->returnValue(false));

    $this->assertFalse($auth->isGranted('TEST'));

用 null 或空数组替换 setMethods() 的参数,或者完全删除调用,都没有任何效果。删除 expects()with() 调用也不会。

您要模拟的方法已声明为最终方法,因此您无法按照描述进行双重测试 in the doc:

Limitation: final, private, and static methods Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.

您可以查看 部分解决方案。

希望对您有所帮助

我能够通过模拟 AuthorizationChecker class 使用的所有内部结构然后将我的模拟注入容器来实现这一点。

    $tokenMock = $this->getMockBuilder( UsernamePasswordToken::class )
                      ->disableOriginalConstructor()
                      ->setMethods( array( 'isAuthenticated' ) )
                      ->getMock();
    $tokenMock->method( 'isAuthenticated' )
              ->willReturn( true );
    $tokenStorageMock = $this->getMockBuilder( TokenStorage::class )
                             ->disableOriginalConstructor()
                             ->setMethods( array( 'getToken' ) )
                             ->getMock();
    $tokenStorageMock->method( 'getToken' )
                     ->willReturn( $tokenMock );
    $authenticationManagerMock = $this->getMockBuilder( AuthenticationManagerInterface::class )
                                      ->disableOriginalConstructor()
                                      ->getMock();
    $accessDecisionManagerMock = $this->getMockBuilder( AccessDecisionManager::class )
                                      ->disableOriginalConstructor()
                                      ->setMethods( array( 'decide' ) )
                                      ->getMock();
    $accessDecisionManagerMock->method( 'decide' )
                              ->willReturn( 'true' );
    $authorizationCheckerMock = $this->getMockBuilder( AuthorizationChecker::class )
                                     ->setConstructorArgs(
                                         array(
                                             $tokenStorageMock,
                                             $authenticationManagerMock,
                                             $accessDecisionManagerMock,
                                             false
                                         )
                                     )
                                     ->setMethods( array( 'isGranted' ) )
                                     ->getMock();
    $authorizationCheckerMock->method( 'isGranted' )
                             ->will( $this->returnValue( true ) );
    $this->getContainer()
         ->set( 'security.authorization_checker', $authorizationCheckerMock );