从本地XML

时间:2016-04-04 15:27:06

标签: php soap mocking phpunit

我想使用文件中的XML来模拟\ SoapClient的响应。

如何在SoapClient从文件返回时创建stdClass对象。

客户端已经包装了SoapClient,因此可以轻松模拟响应。

我的模仿是这样的:

$soapClient->expects($this->once())
            ->method('call')
            ->will(
                $this->returnValue(
                    simplexml_load_string(
                        file_get_contents(__DIR__ . '/../../../Resources/file.xml')
                    )
                )
            );

但是这会返回SimpleXml而不是stdClass。

更新
建议的json_encode / json_decode hack似乎没有处理属性,因为SoapClient返回它们:

SoapClient:

object(stdClass)[4571]
  public 'Lang' => string 'de' (length=2)
  public 'Success' => boolean true

哈克:

  object(stdClass)#27 (3) {
  ["@attributes"]=>
  object(stdClass)#30 (2) {
    ["Lang"]=>
    string(2) "de"
    ["Success"]=>
    string(4) "true"

4 个答案:

答案 0 :(得分:2)

您可以按如下方式对json进行json编码/解码:

$soapClient->expects($this->once())
        ->method('call')
        ->will(
            $this->returnValue(
                json_decode(json_encode(
                    simplexml_load_string(
                        file_get_contents(__DIR__ . '/../../../Resources/file.xml')
                    )
                ))
            )
        );

但我建议明确将预设响应定义为php类。

答案 1 :(得分:1)

如Alex Blex所说,您必须嘲笑__doRequest

请参阅PHP的来源:

  1. https://github.com/php/php-src/blob/f2fd51cb802cec2175a7b92d69c3306615ca29a4/ext/soap/soap.c#L2676
  2. https://github.com/php/php-src/blob/38c337f22eff21ae4123ce1d4354154ee8c63983/ext/soap/php_packet_soap.c#L24

do_request在您的SoapClient实例上调用“ __doRequest”。然后将结果传递到parse_packet_soap,然后解析xml。

答案 2 :(得分:0)

function simpleXML_to_object($obj)
{
  $data = new StdClass();
    if(
        (is_object($obj) && get_class($obj) == 'SimpleXMLElement')
    )
    {
        /*
         * Loop through the children
         */
        if (count($obj->children()))
        {
            foreach ($obj as $key => $value)
            {
                /*
                 * If this is actually an array, treat it as such.
                 * This sort of thing is what makes simpleXML a pain to use.
                 */
                if (count($obj->$key) > 1)
                {
                    if(!isset($data->$key) || !is_array($data->$key))
                    {
                        $data->$key = array();
                    }
                    array_push($data->$key, simpleXML_to_object($value));
                }
                else
                {
                    $data->$key = simpleXML_to_object($value);
                }
            }
        }

        if (count($obj->attributes()))
        {
            foreach ($obj->attributes() as $key => $value)
            {
                $data->$key = (string) $value;
            }
        }
        /*
         * If we have no attributes and no children, treat this as a string.
         */
        if (count(get_object_vars($data)) == 0)
        {
            $data = (string) $obj;
        }
        elseif (strlen( (string) $obj ))
        {
            $data->value = (string) $obj;
        }

    }
    elseif (is_array($obj))
    {
        foreach($obj as $key => $value)
        {
            $data->$key = simpleXML_to_object($value);
        }
    }
    else {
        $data = (string) $obj;
    }

    return $data;
}

答案 3 :(得分:0)

我使用了Alex Blex和gaRex建议来模拟__doRequest方法。 有效。我附上示例代码。

    $localXml = file_get_contents(__DIR__ . '/localResponse.xml');
    $wsdl = 'https://*******.com/path/to/wsdlV5?WSDL';

    $soapClientMock = $this->getMockBuilder(\SoapClient::class)
        ->setConstructorArgs([$wsdl])
        ->setMethods(['__doRequest'])
        ->getMock();

    $soapClientMock->expects($this->once())
        ->method('__doRequest')->will($this->returnValue($localXml));

    $result = $soapClientMock->__call('Function', []);