Phpunit, mock SoapClient是有问题的(mock魔术方法)


Phpunit, mocking SoapClient is problematic (mock magic methods)

我试图用以下代码模拟SoapClient:

$soapClientMock = $this->getMockBuilder('SoapClient')
                ->disableOriginalConstructor()
                ->getMock();
$soapClientMock->method('getAuthenticateServiceSettings')
        ->willReturn(true);

这将不起作用,因为Phpunit mockbuilder没有找到getauthenticateservicessettings函数。这是WSDL中指定的Soap函数。

但是,如果我扩展SoapClient类和getauthenticateservicessettings方法,它确实可以工作。

问题是我有100个SOAP调用,都有自己的参数等,所以我不想模拟每一个SOAP函数,或多或少地重新创建整个WSDL文件…

是否有一种方法来模拟"魔法"方法?

PHPUnit允许您基于wsdl文件存根web服务。

$soapClientMock = $this->getMockFromWsdl('soapApiDescription.wsdl');
$soapClientMock
    ->method('getAuthenticateServiceSettings')
    ->willReturn(true);

请看下面的例子:

https://phpunit.de/manual/current/en/test-doubles.html test-doubles.stubbing-and-mocking-web-services.examples.GoogleTest.php

我通常不直接使用SoapClient类,而是使用使用SoapClient的Client类。例如:

class Client
{
    /**
     * @var SoapClient 
     */
    protected $soapClient;
    public function __construct(SoapClient $soapClient)
    {
        $this->soapClient = $soapClient;
    }
    public function getAuthenticateServiceSettings()
    {
        return $this->soapClient->getAuthenticateServiceSettings();
    }
}

这种方式比模拟SoapClient更容易模拟Client类。

我不能在测试场景中使用getMockFromWsdl,所以我模拟了在后台调用的__call方法:

    $soapClient = $this->getMockBuilder(SoapClient::class)
        ->disableOriginalConstructor()
        ->getMock();
    $soapClient->expects($this->any())
        ->method('__call')
        ->willReturnCallback(function ($methodName) {
            if ('methodFoo' === $methodName) {
                return 'Foo';
            }
            if ('methodBar' === $methodName) {
                return 'Bar';
            }
            return null;
        });

注:我尝试使用__soapCall首先,因为__call被弃用,但没有工作。