我的背景是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解析器。
答案 0 :(得分:0)
我想一个选项是让SoapClientSpyMockFakeSomething extends SoapClient
覆盖__doRequest
方法并使用你到达的XML字符串......