Question

I recently started my journey on testing in php. I am having a hard time getting my head around how to test external services and how a stub will help me assure that the method being testing really behaves as the test promises.

Following example is as taken from the code im unable to understand how to test. I have only included the construct and method in question.

class SoapWrap {


        const WDSL_URL = 'http://traindata.dsb.dk/stationdeparture/Service.asmx?WSDL';

    /**
    *   The WDSL/SOAP Client
    *   @access private
    *   @var \SoapClient $Client
    */
    private $Client; // SOAP client.


    /**
    *   Sets up \SoapClient connection.
    *   @throws \SoapFault upon SOAP/WDSL error.
    */
    public function __construct( \SoapClient $SoapClient )
    {

        try 
        {

            $this->Client = $SoapClient;

        }
        catch( \SoapFault $SoapFault )
        {

            throw $SoapFault;
        }
    }


    /** 
    *   Gets all stations and filters if a filter is passed.
    *
    *   As DSB SOAP service only allows to get all stations 
    *   a filter can be used narrow down the results. 
    *   @param \DSBPHP\Filters\BaseFilter $StationFilte
    *   @return Array with station value objects.
    */
    public function getStations( \DSBPHP\Filters\FilterInterface $StationFilter = null )
    {
        // DSB soap service inforces only method for getting all stations...
        $stations = $this->Client->GetStations()->GetStationsResult->Station;

        if($StationFilter !== null) 
            return $StationFilter->run($stations);

        // return all trains
        return $stations;
    }
}

In the following in test, i have tried to insure that the test do not actully use the SoapClient nor the SoapWrap as it uses the SoapClient as dependecy. The SoapWrap double is because of the ->GetStations call on the soap service inside the getstations() in the code above.

class SoapWrapTest extends PHPUnit_Framework_TestCase {


    private $SoapWrap;


    public function setUp()
    {

        $SoapClient = $this ->getMockBuilder('\SoapClient')
                            ->setMethods(['__construct'])
                            ->disableOriginalConstructor()
                            ->getMock();

        $this->SoapWrap = $this ->getMockBuilder('\DSBPHP\App\SoapWrap')
                                ->setMethods(['__construct', 'getStations'])
                                ->disableOriginalConstructor()
                                ->setConstructorArgs([$SoapClient])
                                ->getMock();
    }


    public function testGetStationsReturnsArray()
    {

        $this->SoapWrap ->expects($this->once())
                        ->method('getStations')
                        ->will($this->returnValue([]));

        $stations = $this->SoapWrap->getStations();
        $this->assertInternalType('array', $stations);
    }
}

I do not understand how this insures that my real soap service SoapWrap actully returns an array, and how i should test this. As i understand it, my test should fail at first, until i implement the code that makes it pass. But with this test, which most be obviously wrong, it always passes. Which takes away any value that i can understand from the test.

I hope you can help me with some examples of how to really test such method.

Was it helpful?

Solution

I do not 100% grasp the example in your question, however if I understand it right you want to test the SoapWrap unit and it has SoapClient as a collaborator.

Now when you create a test if SoapWrap::getStations() returns an array - which it actually always does - the test will always pass. So for your first question about the failed test until it is implemented (as in Test Driven Development (TDD): Test Fails (Red); Write as little code as only needed until it passes (Yellow (or: Green)); Refactor the code (Green (or: Blue))), but you did it the wrong way. You must have written the test before writing the code, e.g. the first time you call the test, PHPunit should crash with a fatal error that the SoapWrap class is not found and can not be instantiated because so far it has not been written.

So delete it now and try to forget the code you've done so far, re-run the test to see it fail and then write it new.

Ensure you've unit-tested the class of $StationFilter before that, too.

For the second part of your question about the mocking: You mock the collaborators, here most likely the SoapClient::GetStations() method. This will spare you to actually run the remote request via SOAP. That easy it is already. You mock the collaborators to test the unit.

OTHER TIPS

Maybe this can help you to try out the web service that you created, you can try to simulate the data transfered with this apps. Check here http://www.soapui.org/

Thanks&Regards, Janitra Panji

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top