Patrik Grinsvall
Patrik Grinsvall

Reputation: 672

Phpunit, mocking SoapClient is problematic (mock magic methods)

Im trying to mock SoapClient with the following code:

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

This will not work since Phpunit mockbuilder does not find the function getAuthenticateServiceSettings. This is a Soap function specified in the WSDL.

However, if i extend the SoapClient class and the getAuthenticateServiceSettings method it does work.

The problem is i have 100s of SOAP calls, all with their own parameters etc. so i dont want to mock every single SOAP function and more or less recreate the whole WSDL file...

Is there a way to mock "magic" methods?

Upvotes: 14

Views: 11392

Answers (3)

solarc
solarc

Reputation: 5738

I wasn't able to use getMockFromWsdl for a test scenario, so I mocked the __call method which is called in the background:

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

P.S. I tried using __soapCall first since __call is deprecated but that didn't work.

Upvotes: 3

user1777136
user1777136

Reputation: 1756

PHPUnit allows you to stub a web service based on a wsdl file.

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

See example here:

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

Upvotes: 28

zuzuleinen
zuzuleinen

Reputation: 2634

I usually don't work with the \SoapClient class directly, instead I use a Client class which uses the SoapClient. For example:

class Client
{
    /**
     * @var SoapClient 
     */
    protected $soapClient;

    public function __construct(SoapClient $soapClient)
    {
        $this->soapClient = $soapClient;
    }

    public function getAuthenticateServiceSettings()
    {
        return $this->soapClient->getAuthenticateServiceSettings();
    }
}

This way is easier to mock the Client class, than mocking the SoapClient.

Upvotes: 5

Related Questions