如何测试/比较/参数匹配要传递给SoapClient的stdClass参数?

时间:2012-12-11 02:43:40

标签: php soap wsdl simplexml stdclass

我的背景是Java。我不知何故认为潜入PHP会很有趣。

我有一个WSDL文件,其中定义了一些我需要调用的方法。每种方法通常都有一个请求和一个定义的响应类型。这些类型都是一层或两层深,没有属性 - 只有元素。没有什么花哨。 几乎所有方法都需要一些常见的参数,比如“username”和“password”。

我以为我会测试所有这些,所以我创建了一个处理传递标准参数的间接方法。生产代码如下所示:

class PaymentManager implements IPaymentManager {

  public function __construct($soapClient, $username, $password, ...) {
    $this->soapClient = $soapClient; 
    $this->username = $username;
    ...
  }

  public function chargeCustomer($price, $customerId) {
    // prepare message
    $message = new stdClass();
    $message->ChargeMethodRequest = new stdClass();
    $message->ChargeMethodRequest->Username   = $this->username;
    $message->ChargeMethodRequest->Password   = $this->password;
    $message->ChargeMethodRequest->Price      = $price;
    $message->ChargeMethodRequest->CustomerID = $customerId;

    // make the actual call
    $result = $this->soapClient->chargeMethod($message->ChargeMethodRequest);

    // verify successful result
    if ($result->ChargeMethodResponse->Result === "SUCCESS") {
      throw new Exception("whopsie");
    }
  }

现在,诀窍是为此编写单元测试,而无需使用SoapClient的实际实例。我开始使用SoapUI并生成示例消息,但它们在PHP文件中作为静态字符串,我可以从单元测试中引用。所以我想象这样的事情:

class WebServiceClientTest extends DrupalUnitTestCase /* yup, sad and true */ {

  public function test_charge_method_happy_path() {
    $soapClientMock = new SoapClientMock();
    $testee = new WebServiceClient($soapClientMock, $un, $pw, ...); 

    // arrange
    $successResponse = parseToStdClass(WebServiceClientMessages::RESPONSE_OK);
    $expectedMessage = parseToStdClass(WebServiceClientMessages::REQUEST_EXAMPLE_1);
    given($soapClientMock->chargeMethod($expectedMessage))->willReturn($successResponse);

    // act
    $testee->chargeCustomer("10.00", "customerId123");

    // assert
    verify($soapClientMock).chargeMethod($expectedMessage);
  }
}

首次尝试,Phockito:失败,因为SoapClient是一个“本机”类,而且这些类不能与PHP中的Reflection*一起使用。

如果做不到这一点,我写了一个SoapClientMock类,我希望将方法调用存根,并验证交互。这不是什么大问题,但问题是参数匹配。

如何获取示例消息(XML字符串),将它们解析为可以与SoapClient所需的stdClass对象进行比较以正确绑定内容的内容?根据我的理解,对象比较是硬编码的,并查看两个对象是否属于同一类。

SimpleXMLElement是我的第一个希望,但是与stdClass对象进行比较并不容易,主要是因为SimpleXMLElement想要使用名称空间。

序列化不起作用,因为SimpleXMLElement对象是“本机”类。

有人建议做json_decode(json_encode($object))然后进行比较,除了SimpleXMLElement失败之外几乎无效,因为没有指定命名空间就无法获取子节点(并且我需要使用多个节点),所以$expectedMessage不包含所有元素。

我目前正在使用SAX编写自己的“xml string to stdClass”解析器。

但是等等 - 我想要的是确保PaymentManager正确填充chargeMethod的有效负载 - 为什么我最终写了一个SAX解析器。

1 个答案:

答案 0 :(得分:0)

我想一个选项是让SoapClientSpyMockFakeSomething extends SoapClient覆盖__doRequest方法并使用你到达的XML字符串......