0

現在、値オブジェクトに基づいて XML を生成し、HTTP 経由で XML を送信し、XML 応答を解析して 2 番目の値オブジェクトに戻すクラスのテストに取り組んでいます。この場合、生成された XML と、特定の XML に基づいて解析された値オブジェクトをテストしたいと思います。

クラスは次のようになります。

class MyClient
{
    public function send(RequestValues $request)
    {
        $document = $this->generateMessage($request);
        $response = $this->request($document);

        return $this->parseResponse($response);
    }

    protected function generateMessage(RequestValues $request)
    {
        $document = new DomDocument;
        // Do stuff with $request

        return $document;
    }

    public function request(DomDocument $document)
    {
        $client = $this->getHttpClient();
        $client->setRawBody($document->saveXml());
        // Configure client

        return $client->send();
    }

    public function parseResponse(Response $response)
    {
        $parameters = new ResponseValues;

        $document = new DomDocument;
        $document->loadXml($response->getBody());

        // Fill in $parameters
        return $parameters;
    }
}

私は2つのことをテストしたいと思います:

  1. 特定のRequestValues引数を指定すると、生成される XML は次のようになります。$string
  2. 特定の XML 応答値 (HTTP クライアントがモックされる) が与えられると、 は次の値ResponseValuesに等しくなければなりません。$object

#1のテストを書いていますが、これはコールバックを介してのみ達成できると思います。ただし、テストが失敗した場合、コールバックはあまり有用な情報を提供しません。このメッセージのみ:

DOMDocument オブジェクト () が指定されたコールバックによって受け入れられることをアサートできませんでした。

テストは次のようになります。

public function testRequestContainsValidXml()
{
    $client  = $this->getMock('MyClient', array('request'));

    $message = '';
    $client->expects($this->once())
           ->method('request')
           ->with($this->callback(function($object) use ($message) {
                return
                    ($object instanceof DomDocument)
                 && ($object->saveXml() === $message);
            }));

    $request = new DirectoryRequest;
    $client->send($request);
}

問題は、通常の文字列比較ができるようにテストを改善するにはどうすればよいかということです。「文字列 X は Y と等しくない」という phpunit を取得したいと思います。これにより、デバッグが大幅に容易になります。

PS。このクラスの完全なコードは GitHub で入手できます。当然、上記の例は単純化されたバージョンです。実際のクラスは次のとおりです: https://github.com/juriansluiman/SlmIdealPayment/blob/master/src/SlmIdealPayment/Client/StandardClient.php#L58

PPS。テストするためにコードを変更する必要がある場合、それは問題ではありません。パブリック API を同じに保ちたいだけです (つまり、呼び出しResponseValues send(RequestValues $request)

4

1 に答える 1

0

あなたのクラスMyClientは、それがファサードであることを示唆しています。UnitTests のコンテキストでファサードをテストするには、通常、まずそのファサードの共同作業者であるすべてのユニットをテストする必要があります。

通常、テスト対象のユニットではなくコラボレーターをモックするため、テスト対象のユニットをモックしていてもコラボレーターではないため、テストのセットアップは間違っているように見えますMyClient

例えば:

MyClient::parseResponse()メソッドが期待されるオブジェクトを返すかどうかをテストしResponseValuesます。したがってResponse、この場合はコラボレーターであるため、 をモックします。

おそらく他のコラボレーター ( ) もモックしたいでしょうResponseValuesが、それは注入できない隠された依存関係であるためできません (MyClientそのような の作成を制御できるファクトリを注入することでこれを解決できますResponseValues)。

テストは以上です。モックをMyClient::parseResponse()介してフィクスチャ XML を挿入Responseし、戻り値に対してアサーションを実行します。

リクエストに有効な XML が含まれているかどうかをテストするケース ( testRequestContainsValidXml()) についても、その複雑な形式で実行する必要はないと思います。ここに HTTP クライアントがあるように聞こえますが、動作することだけをテストする必要があり、XML でも動作するかどうかは気にしません。動作する場合は、XML でも動作するからです。有効な XML をテストする理由は、クライアントをテストするためではありません。したがって、そのテストをクライアントの単体テストから除外してください。

ところで文字列のアサーション。は:

$this->assertSame($expected, $actual);

Phpunit は、文字列間の素敵な差分を表示します。他の一部のプログラマー/テスターも、差分が読みやすくなるように XML を比較するときに XML 正規化を適用していました。XMLで意味のない空白を問題なく処理できる場合は、適切な形式を出力する方法や関連する PHP XMLのような Q&A が役に立つかもしれません。

これであなたが直面している問題のケースを少し指摘し、問題に対するあなたの視野を広げることができれば幸いです. 現在のモックの使用法に批判的に疑問を投げかけることで、あなたは最も遠くまで来ていると思います。私が示す例では、アサーションを行うためではなく、コラボレーターを提供するためにモックを完全に減らしました。アサーションは、テスト対象のユニットでのみ行われます。ここでは、模範的なMyClient.

于 2013-09-27T14:32:42.203 に答える