私のバックグラウンドは Java です。PHPに飛び込むのは楽しいだろうとどういうわけか思いました。
呼び出す必要があるいくつかのメソッドが定義された WSDL ファイルがあります。通常、各メソッドには 1 つの要求と 1 つの応答タイプが定義されています。これらのタイプはすべて 1 レベルまたは 2 レベルの深さで、属性はなく、要素のみです。派手なものはありません。ほとんどすべてのメソッドには、「ユーザー名」や「パスワード」などの共通の引数が必要です。
これらすべてをテストしてみようと思ったので、標準引数の受け渡しを処理するインダイレクションを作成しました。製品コードは次のようになります。
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 オブジェクトと比較できるようにするにはどうすればよいでしょうか? 私が理解していることから、オブジェクトの比較はハードコードされており、2 つのオブジェクトが同じクラスであるかどうかを調べます。
SimpleXMLElement は私の最初の希望でしたが、主に SimpleXMLElement が名前空間を使用したいという理由から、これを stdClass オブジェクトと比較するのは簡単ではありません。
SimpleXMLElement オブジェクトは「ネイティブ」クラスであるため、シリアル化は機能しません。
名前空間を指定せずに子ノードを取得する方法がないため(そして使用する必要があるノードが複数あるため)、 SimpleXMLElementjson_decode(json_encode($object))
が失敗することを除いて、ほとんど機能しました。そのため、$expectedMessage
すべての要素が含まれているわけではありません.
私は現在、SAX を使用して独自の「xml 文字列を stdClass に変換する」パーサーを作成しています。
でも待ってください - 私が望んでいたのは、 PaymentManager が chargeMethod のペイロードを適切に設定することだけでした - なぜ私は SAX パーサーを書くことになったのですか?