我的背景是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 解析器。