Aine
Aine

Reputation: 2708

Phpunit - mocking SoapFault->getMessage()

I'm connecting to a third party service using SOAP. This service will return SoapFaults some times. Because this is expected, I want to test this, by mocking the SoapFaults. There are five standard SoapFaults it will return.

Here is the start of a real SoapFault:

object(SoapFault)#7 (11) {
  ["message":protected]=>
  string(19) "{ 'INVALID_INPUT' }"

I am interested in this message. In my code I use $e->getMessage().

catch (SoapFault $e)
{
    // Catch any Soap faults and convert to an error message
    switch ($e->getMessage())
    {
        case "{ 'INVALID_INPUT' }":
            $this->addError(self::INVALID_INPUT);
            return FALSE;

but I cannot figure out how to mock the SoapClient response. The SoapClient object doesn't appear to take in any input to set the message, and the method getMessage() is final, so I can't mock it.

Any ideas would be appreciated. Thanks.

Upvotes: 1

Views: 2849

Answers (3)

Aine
Aine

Reputation: 2708

I want to thank hakre for his comment. This is exactly what I wanted.

The SoapFault extends Exception, which expects an input of ($message, $code, $previous). But the SoapFault expects ($faultcode, $faultstring, $faultactor, $detail, $faultname, $headerfault). This is what threw me.

The $faultstring maps to the exception message.

So to mock it, I did:

$mock_soap->expects($this->once())
                         ->method('checkVat')
                         ->will($this->throwException(new SoapFault('a', "Error Message")));

And in my real code $e->getMessage() now returns 'Error Message'

Upvotes: 1

hakre
hakre

Reputation: 198217

Next to what edorian answered, there should be no need to test that a third-party component works as announced. Don't write tests for components you don't have written the code (or for which you can not write code, if they are broken, they're broken and you're lost).

Just test that your code works as expected. You should be able to mock your own code.

Example: Your code will always break if code or data of it is missing, e.g. files of your application get partially deleted under circumstances. Do you write tests for such scenarios? Naturally not.

You can however write yourself an integration suite that automatically tests if certain remote dependencies provide the expected interface and responses. But I would put that suite apart from your testsuites that cover your own code-base.

Additionally you can create your own assertion functions that can be used in each testcase, for example one for SoapClient Exception Message.

Upvotes: 1

edorian
edorian

Reputation: 38981

There should be no need to mock SoapFault. You can just use the real exception (usually exceptions are not mocked for testing as they are Value objects) and mock the SoapClient to throw your prepared exception.

By doing so you get around not being able to mock getMessage because you build the SoapFault in your test case like shown below.

As I've had troube figuring out what exactly your problem was i build a little test case to make sure it works out. As it was there already i guess the code explains it better than i could.

Test example:

<?php

class SoapFaultTest extends PHPUnit_Framework_TestCase {

    public function testSoapFault() {
        $soapFault = new SoapFault("test", "myMessage");
        $soapClient = $this->getMockBuilder('SoapClient')
            ->setMethods(array('methodOnService'))
            ->disableOriginalConstructor()
            ->getMock();

        $soapClient->expects($this->once())
            ->method('methodOnService')
            ->will($this->throwException($soapFault));

        $x = new Consumer();
        $this->assertSame(
            "InvalidInput",
            $x->doSoapStuff($soapClient)
        );  
    }   

}

class Consumer {

    public function doSoapStuff(SoapClient $soapClient) {
        try {
            $soapClient->methodOnService();
        } catch(Exception $e) {
            if($e->getMessage() == "myMessage") {
                return "InvalidInput";
            }   
        }   
    }   
}

Outputs:

 phpunit SoapFaultTest.php 
PHPUnit 3.6.3 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.75Mb

OK (1 test, 2 assertions)

The assertion is kept simple but you should be easily able to adapt this for your way of handling errors

Upvotes: 5

Related Questions