3

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.

4

2 回答 2

2

我没有 100% 理解您问题中的示例,但是如果我理解正确,您想测试该SoapWrap单元并且它SoapClient作为合作者。

现在,当您创建一个测试时,如果SoapWrap::getStations()返回一个数组 - 它实际上总是这样做 - 测试将始终通过。因此,对于您在实施之前关于失败测试的第一个问题(如在测试驱动开发(TDD)中:测试失败(红色);只需要编写尽可能少的代码,直到它通过(黄色(或:绿色));重构代码(绿色(或:蓝色))),但你做错了。您必须在编写代码之前编写测试,例如,第一次调用测试时,PHPunit 应该会崩溃并出现致命错误,即SoapWrap找不到该类并且无法实例化,因为到目前为止还没有编写。

所以现在删除它并尝试忘记你到目前为止所做的代码,重新运行测试以查看它是否失败,然后重新编写它。

确保你也对$StationFilter之前的类进行了单元测试。

对于您关于嘲笑的问题的第二部分:您嘲笑合作者,这很可能是SoapClient::GetStations()方法。这将使您不必通过 SOAP 实际运行远程请求。这已经很容易了。你嘲笑合作者来测试这个单元。

于 2013-09-25T19:07:43.007 回答
0

也许这可以帮助您试用您创建的 Web 服务,您可以尝试模拟使用此应用程序传输的数据。在这里查看http://www.soapui.org/

谢谢&问候, Janitra Panji

于 2013-09-25T18:47:57.997 回答