前回(第35回)はwwを使ってWebのダブルとなるサーバを作り、スパイ機能を使ってクライアントからのリクエストの状況を目視確認する方法を説明しました。
今回は、ミニブログへのメッセージ投稿を通じて、wwを自動化テストに組み込む方法を説明します。
RSpecの自動テストの中からサーバを起動停止する
wwは、単一のサーバプロセスとして起動させるほかに、自動化テストの中で定義・起動・停止するためのAPIを備えています。前回作ったダブルサーバを、RSpecから起動・停止するテストコードは次のようになります。
アクションを定義しているブロックは、前回のWW::SpyEyeを使った場合とまったく同じになります。 WW::Server.build_dobule(port)は引数で指定されたポートで起動するダブルサーバを定義します。つまり、この例では、前回作ったのと同じダブルサーバを3080番ポートで起動するように定義しています。また、二重起動防止やテスト中からの操作のために、 WW::Server.[]=(identifier, server)メソッドでwwが用意しているコンテナに入れています。
サーバを起動させるには、WW::Server.start_once(identifier)メソッドを呼び出します。このメソッドは、指定したidentifierのダブルサーバが起動していない場合は起動させ、すでに起動している場合はスパイなどの呼び出し情報をリセットします。また、ここで起動したサーバは、スクリプトの終了時に自動的に終了します[1]。
サーバへのリクエストをモックする
では、メッセージの投稿機能を実装しましょう。サーバ側のWebAPIは「投稿ユーザ名とメッセージ内容を、/messagesにPOSTする」というものとします。認証機能などは、いまは考えません。
リクエストの有無をモックで検証する
wwでは2種類の方法でモックを定義できます。
一つ目はWW::Server.build_double()のブロック内でmock()メソッドを使い、あらかじめ定義する方法です。これはすべてのテストケースで有効にしたいモック(たとえば、ログイン機能など)を定義するのに便利です。もう一つは、 WW::Server.mock(identifier)で後から定義する方法です。こちらは、必要となるモックをテストケースごとに定義できます。
今回はpost_entryに関するテストケースでのみ使いたいため、後者の方法でモックを定義します。指定したサーバへのモック呼び出しの有無は、after { } ブロックでのWW::Server.verify(identifier)で検証します。
まずは、モックの役割の一つである、「呼び出されなかった場合にその旨を通知する」機能を試すため、MiniblogClient#post_entry()を空のメソッドとして定義し、テストを実行してみます。
この状態でテストを実行します。モックしている、つまり呼び出しを期待しているアクションが呼ばれないため、テストが失敗します。
予想通りテストが失敗することを確認できたので、MiniblogClient#post_entryを実装します。
これでテストが通るようになりました。試しに実行してみましょう。
期待するリクエストの内容つきでモックする
さらに、いま述べたようなリクエストの有無だけを検証するのではなく、リクエストの内容が期待するものかどうかも検証できます。リクエストの内容を検証するには、mock()メソッドの第二引数として期待するパラメータ名と値をHashで渡します。
たとえば、送信されるmessageが「こんばんは」であることを検証するには、次のように定義します。
こうすると、@client.post_entry("moro", "こんばんは")の場合にはテストが成功し、 @client.post_entry("moro", "こんにちは")と呼び出した場合にはテストが失敗するようになります。"user"パラメータについては特に検証しないため、@client.post_entry("morohashi", "こんばんは")などという呼び出しでも テストは成功します。リクエストの中で特に検証したいパラメータのみを指定するとよいでしょう。
スパイのリクエストの状況を検証する
前回紹介した、スパイの機能も使えます。
たとえば、前回は目視確認した「MiniblogClient#entry_listで、3回(friendsの数だけ)/messages/:users.jsonにアクセスしていること」を自動化テスト内で検証するには、次のようなテストを書きます。
スパイとして定義したアクションへのリクエストは、WW::Server#requestsメソッドで取得できます。 例では回数だけを検証していますが、このリクエストオブジェクトからHTTPメソッドやパス、クエリパラメータなどを取得して検証できます。ただし、あくまでスパイですので、モックのように自動的に検証したりはしません。スパイしたリクエストを取得し、この例のshould have(3).requestsのように自分で検証する必要があります。
このテストを実行すると、次のようにパスします。
モックとスパイを使い分ける判断基準ですが、筆者の感触では、サーバ側のAPIを含めて設計していたり、そのAPIを始めて使ったりと「自分が作っているものがハッキリしない」場合はスパイから取得したリクエストをもとに試行錯誤するほうがよいと感じています。その後、ある程度動くものができてからは、モックを使ってテストすべきことを明確にすると、意図を表現できているよいテストになりそうです。
おわりに
今回は、wwを自動化テストから使い、Webサーバとの間で行われているインタラクションを検証する方法を説明しました。
wwは現在も開発中であり、機能のリクエストやバグ報告、よりよいAPIの提案なども募集中です。アイディアがありましたらhttp://github.com/moro/ww/issuesやTwitterの@moroなどで、いろいろお聞かせいただければ嬉しく思います。
外部サービスとの連携は、アプリケーション開発の中でも特に難しく感じることが多い場面です。wwが少しでもその不安を取り除き、楽しくテストを書くために役立てればうれしく思います。