0

我的背景是Java。我以某种方式认为潜入 PHP 会很有趣。

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

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

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 是一个“本机”类,并且不能Reflection*在 PHP 中使用。

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

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

SimpleXMLElement 是我的第一个希望,但这与 stdClass 对象相比并不容易,主要是因为 SimpleXMLElement 希望使用所有的命名空间。

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

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

我目前正在使用 SAX 编写自己的“xml 字符串到 stdClass”解析器。

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

4

1 回答 1

0

我想一种选择是让 aSoapClientSpyMockFakeSomething extends SoapClient并覆盖该__doRequest方法并使用您到达那里的 XML 字符串...

于 2012-12-11T02:43:39.567 回答