連載
» 2013年02月20日 18時00分 公開

Capybara-Webkit+Cucumber+Sinon.JSでJavaScriptのテストはここまで変わるフレームワークで実践! JavaScriptテスト入門(5)(3/3 ページ)

[清家巧,TIS コーポレート本部 戦略技術センター]
前のページへ 1|2|3       

Sinon.JSを使ってAjaxのテスト

 ここまでのテストではgetJSONが完了するまでの間に表示される「確認中です...」が実際に行われているかテストしていませんでした。

 もちろん、この内容もテストするべきでしょう。しかし、サーバサイドから非同期的に値を取得して更新を実施するため、画面上のメッセージが更新されるタイミングはサーバの応答時間次第、画面上のメッセージの更新内容は値次第となってしまいます。

 テストのためのサーバを立てるのも大変ですし、Webブラウザ側のテストのためにサーバに手を入れるのは美しくありません。ここでSinon.JSの出番がやってきます。

Fake Serverでダミーのレスポンスを返してAjaxをテスト

 Sinon.JSは冒頭で紹介したとおり、スタブ、モック、スパイなどの機能を提供します。上記の問題を解決するために、Sinon.JSの「Fake server」の機能を利用します。

 Fake ServerはAjaxのリクエストに対して実際の通信を行わずダミーのレスポンスを戻すことができます。ここでは、APIへの通信をフックして通信の間に表示される「確認中」が出ることと、{status: ok}を応答として受け取ったときに利用可能ですと表示されることをテストします。

 利用の前に「/features/js/」にSinon.JSをダウンロードしておきます。

mkdir features/js
cd features/js
wget http://sinonjs.org/releases/sinon-1.6.0.js

 次に、sample.featureとsteps.rbに以下を追記します。

 シナリオ: 利用可否の確認中メッセージが表示された後利用可のメッセージが表示されること。
  前提 "http://localhost:8000/"を表示
  かつ Sinon.JSを利用する
  かつ fakeserverを設定する
  もし "ねこ"を入力
  かつ 確認ボタンを押下
  ならば メッセージ"確認中"が表示される
  もし ユーザー名が利用可の応答を受け取る
  ならば メッセージ"利用可能です"が表示される
features/sample.featureに追記
前提 'Sinon.JSを利用する' do
  f = File.open('features/js/sinon-1.6.0.js', "r")
  sinon = f.read;
  page.execute_script sinon
  f.close
end
前提 'fakeserverを設定する' do
  page.execute_script <<-JS
    server = sinon.fakeServer.create();
  JS
end
もし 'ユーザー名が利用可の応答を受け取る' do
  # 最後に受けたRequestに対して応答する
  page.execute_script <<-JS
    var idx = server.requests.length - 1;
    server.requests[idx].respond(200, {"Content-Type": "application/json"}, '{"status":"ok"}');
  JS
end
features/step_definitions/steps.rbに追記

 Capybaraを通してSinon.JSのロード、Fake Serverの実行などを行います。JavaScriptを実行するときはCapybaraの「execute_script」「evaluate_script」を使います。

 「sinon.fakeServer.create()」を設定した時点で、Ajaxの通信は実際には行われなくなり、Sinon.JSからのダミーのレスポンスを受け取るようになります。ダミーのレスポンスを返す部分は、ステータスコードとヘッダとボディの3つを設定します。

spyでどのように呼ばれたか確認する

 次に、Sinon.JSを用いてgetJSONの引数が正しく設定されているか確認してみます。引数のチェックや呼ばれた回数などをチェックするにはspyを使います。

 さらに、features/sample.featureにシナリオを追記します。

 シナリオ: getJSONの引数チェック
  前提 "http://localhost:8000/"を表示
  かつ Sinon.JSを利用する
  かつ getJSONにspyを設定する
  もし "いぬ"を入力
  かつ 確認ボタンを押下
  ならば 引数"いぬ"でgetJSON処理を実行する
  かつ getJSON処理が1回実行されている
  もし "ねこ"を入力
  かつ 確認ボタンを押下
  ならば 引数"ねこ"でgetJSON処理を実行する
  かつ getJSON処理が2回実行されている
features/sample.featureに追記

 features/step_definitions/steps.rbにも以下の内容を追記します。

前提 'getJSONにspyを設定する' do
  page.execute_script <<-JS
    var spy = sinon.spy($, "getJSON");
  JS
end
ならば /引数\"(.+)\"でgetJSON処理を実行する/ do |name|
  js = "spy.calledWith('./status', {'name': \'#{name}\'})"
  ok = page.evaluate_script js
  unless ok
    raise "unexpected param"
  end
end
ならば /getJSON処理が(\d+)回実行されている/ do |expect|
  count = page.evaluate_script <<-JS
    spy.callCount;
  JS
  if count.to_i != expect.to_i
    raise "unexpected callcount #{count} != #{expect}"
  end
end
features/step_definitions/steps.rbに追記

 $オブジェクトのgetJSONメソッドに対してspyを設定し、spyの「CalledWith」「callCount」を使って想定した引数で呼び出されているかをテストしています。CapybaraによってJavaScriptの実行結果をRuby側で取得して、その結果を元に想定値と現実の比較を行っています。

 ここまでの修正で全体のテスト結果は、こうなりました。

JavaScriptのテストもガンガン行こうぜ!

 というわけで、本記事では非常に簡単なWebアプリケーションを対象にCapybara-WebkitとSinon.JSを組み合わせ、Cucumberで記載したテストをヘッドレスに実行しました。

 通常、「Webブラウザでページを開いて」「何かを入力して」「ボタンを押して」と実際に動作確認をしなければならないと開発者に思われていた部分について、コマンドラインからのテスト実行であっという間にテストできるため、テストを書く手間さえ惜しまなければ非常に楽ができるはずです。

 今回はCapybara-Webkitを記事では取り上げましたが、同様のものとして「Poltergeist」(Capybara向けPhantomJSドライバ)があります。

 CucumberはJavaScriptのテストという観点からは少し逸脱しますがWebページをテストする際にCapybara/DSLと組み合わせたことでユーザーの操作を自動化でき、ユーザー操作に付随して動作するJavaScriptの動作確認も可能である点は非常に省力化が期待できると思います。

 また、テスト対象がWebアプリケーションであれば、そのアプリケーションがPerl/PHP/PythonなどのRuby以外の言語で書かれていてもテストが可能なのは非常に大きいと思います。

 Sinon.JSは今回の記事内では少々トリッキーな利用方法をしていましたが、Fake Serverとspyの強力な機能はお伝えできたと思います。

 Sinon.JSは記事内で利用しなかった強力な機能もあるので、これまでの連載で取り上げられている単体テスト向けのフレームワークであるQUnitやJasmine、JSTestDriverなどとの連携させることでテストの適用範囲が広げられるでしょう。

 これまでは「JavaScriptだからテストコードは書かない」という世界もありましたが、本連載で取り上げたようにJavaScriptをテストするためのフレームワークが十分に実用可能になっています。

 これからはJavaScriptのテストもガンガン書いて快適なJavaScriptライフを送りましょう!

前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

6月16日にフォーマット統一のため利用規約を変更します

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。