Ajaxのテスト Selenium

7.Ajaxのテスト
Ajaxで動作するプログラムは、いままでの方法ではテストできません。サーバ側だけでプロセスが完了せずブラウザ側にあるJavaScriptと連動して動作しているからです。では、どのような方法でテストしたらよいでしょうか。簡単なプログラムを作成し、その方法を学びましょう。

7-1.プロジェクトの複写
プロジェクトAppli002を新しいプロジェクトTest004へコピーします。
(1) Appli002上で右クリックしてコピーを選択する

(2) プロジェクト名(N)を新しいプロジェクトTest004にする

(3) データベースの再作成
テストの場合はProject_testの環境で実施されるため、Project_developmentだけでは動作しません。
ここではProject_developmentを一旦ドロップし、再度DB環境をクリエイトしましょう。

Netbeansで[Rakeタスクを実行/デバック..]を選択
    フィルタ(F):
    パラメータ(P):
    一致するタスク(M): db:drop

Netbeansで[Rakeタスクを実行/デバック..]を選択
    フィルタ(F):
    パラメータ(P):
    一致するタスク(M): db:create:all


7-2.Ajaxを利用するための修正
(1) レイアウトファイルの作成
Ajaxを利用するため、基本的なレイアウトファイルを作成します。


/app/views/layouts/triangle.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Test004: <%= controller.action_name %></title>
<%= javascript_include_tag :defaults %>
</head>
<body><%= yield %>

</body>
</html>

(2) ビューの修正

/app/views/triangle/index.html.erb

(3) コントローラの修正


/app/controllers/triangle_controller.rb
class TriangleController < ApplicationController
def index
end

def calculate
@triangle = Triangle.new(params[:triangle])
if @triangle.valid?
x=@triangle.a.to_f
y=@triangle.b.to_f
z=@triangle.c.to_f
fg="ON"
fg="off" if x+y<=z
fg="off" if x+z<=y
fg="off" if y+z<=x

if fg=="ON" then
s=(x+y+z)/2
area=Math.sqrt(s*(s-x)*(s-y)*(s-z))
@result = "辺の長さ #{x}, #{y}, #{z} の三角形の面積は#{area}"
else
@result = "辺の長さ #{x}, #{y}, #{z} では三角形はできない"
end
render :partial => "results" # 結果はパーシャルで返す
else
render :partial => "error_messages"
end
end

end

(4) 結果の対応


/app/views/triangle/_results.html.erb

<%= "#{@result}" %>




/app/views/triangle/_error_messages.html.erb

<%= error_messages_for :triangle %>

(5) プログラムの実行
実際の動きは次のようになります。

7-3.テストパターンの作成
(1) NGのテスト(その1)
三角形が成り立たない場合のテストを考えましょう。三辺が1,2,3では成り立たないので、これをテストケースにします。
Ajaxを使用してメソッドを呼ぶときはxhrという命令を使って呼びます。まずは正常に戻ってくるか確認しましょう。


/test/functional/triangle_controller_test.rb
require 'test_helper'

class TriangleControllerTest < ActionController::TestCase
test "NG data" do
xhr :post, :calculate, :triangle=>{:a=>"1", :b=>"2", :C=>"3"}
assert_response :success
end
end

NetBeansで[テスト]を選択し実行します。

(2) NGのテスト(その2)
次にテンプレートが正しく利用されたか確認しましょう。


/test/functional/triangle_controller_test.rb
require 'test_helper'

class TriangleControllerTest < ActionController::TestCase
test "NG data" do
xhr :post, :calculate, :triangle=>{:a=>"1", :b=>"2", :C=>"3"}
assert_response :success
assert_template "_results"
end
end

NetBeansで[テスト]を選択し実行します。

renderingはindex.htmlになっています。これはパーシャルhtmlである_results.htmlはAjaxによってindex.htmlに取り込まれ、それがレスポンスとなるからです。

(3) NGのテスト(その3)
確認するテンプレートをindex.htmlに変更します。


/test/functional/triangle_controller_test.rb
require 'test_helper'

class TriangleControllerTest < ActionController::TestCase
test "NG data" do
xhr :post, :calculate, :triangle=>{:a=>"1", :b=>"2", :C=>"3"}
assert_response :success
assert_template "index"
end
end

NetBeansで[テスト]を選択し実行します。

(4) NGのテスト(その4)
最後に内容を検証しましょう。ここでは“面積は”という字句がないことを確認します。


/test/functional/triangle_controller_test.rb
class TriangleControllerTest < ActionController::TestCase
test "NG data" do
xhr :post, :calculate, :triangle=>{:a=>"1", :b=>"2", :C=>"3"}
assert_response :success
assert_template "index"
assert_nil assigns(:result).index("面積は")
end
end

NetBeansで[テスト]を選択し実行します。

assigns(:result)がnilオブシェクトとなっています。_resultarea.html からindex.htmlへ状態が遷移してしまったためでしょうか。

(5) NGのテスト(その5)
最後的に表示するhtmlの内容で検証しましょう。ここでは“できない”という字句があることを確認します。


/test/functional/triangle_controller_test.rb
class TriangleControllerTest < ActionController::TestCase
test "NG data" do
xhr :post, :calculate, :triangle=>{:a=>"1", :b=>"2", :C=>"3"}
assert_response :success
assert_template "index"
assert_select "div#results", /できない/
end
end

NetBeansで[テスト]を選択し実行します。

<div id=results></div>の中は“”だとの判定です。確かに実行時のhtmlソースも空のままです。Ajaxを利用したプログラムは詳細なテストできないようです。

7-4.Selenium IDEのインストール
(1) Firefoxのインストール
SeleniumIDEはFirefox3.5上で動作するので、Firefox3.5をインストールします。
Firefoxの公式サイトhttp://mozilla.jp/firefox/ から「旧バ−ジョンのダウンロード」を選択し、Firefox Setup 3.5.8.exe をダウンロードします。
・タウンロードしたexeファイルを実行します。

(2) Seleniumのインストール
・同じサイトでアドオンボタンを押し、「Selenium」を検索します。
・結果画面に[firefoxへインストール]ボタンがあるのでクリックします。

7-5.Selenium IDEの起動
(1) まずFirefoxを立ち上げ、ツールから[selenium IDE(N)]を選択します。

7-6.テストパターンの自動作成
(1) SeleniumIDE画面の右上にある赤いボタンが「記録中」であることを確認します。

(2) Fairfox画面に戻って、想定しているテストパターン1を実行します。
入力したデータがすべて記録されていくのがここから分かります。

(3) 動作の検証を組み込みます。
Firefox画面で「三角形はできない」を選択し右クリックします。その中から[verifyTextPresent 三角形はできない]を選びます。
これで、1,2,3というデータを入力すると、”三角形はできない”と表示されることを確認するコマンドとなります。

(4) 記録されたコマンドの実行
SeleniumIDE画面の[テストスイート全体を実行]ボタンをクリックします。
コマンドが実行され、Firefox画面も変化していくのが分かります。

(5) Ajaxでの問題点の解消
記録されたコマンドを繰り返し実行できることが分かったが、問題点もでてきました。検証がエラーとなっています。正しければ緑色の背景色がつくはずです。

これはAjaxを利用した場合、Webページ全体のリロードが発生しないため検証タイミングなく、非同期に検証コマンドを実行してしまい、“三角形ができない”という結果表示の前に判断しているからです。
そこで表示されるまで待つコマンドを追加します。

(6) テストの実行
検証も正しく動作し背景色が緑になっています。

(7) テストパターンの作成

(8) テストパターンの実行

7-7.主なコマンド
Seleniumのコマンドは大きく分けてActionとCheckの二種類があります。ActionはWebアプリケーションにリクエストを行うためのもので、CheckはWebアプリケーションからのレスポンス内容を検証するためのものです。
(1) Action

コマンド意味
open [url] [ ]urlを開く
type [id] [text]input要素の内容を設定する
select [id] [lavel=text]select要素の選択肢として表示される文字列を設定する。
select [id] [value=value値]select要素のvalue値を設定する
select [id] [index=index番号]select要素の位置(0から始まる)を設定する
check [id] [ ]チェックボックスラジオボタンにチェックを付ける
uncheck [id] [ ]チェックボックスラジオボタンのチェックを外す
click [id] [ ]リンクやボタンをクリックする
submit [id] [ ]formのsubmitを行う。submitボタンがないとき使う
keyPress[id][keycode]キーボードのキーを押した設定をする
clickAndWait [id] [ ]リンクやボタンをクリックしページがリロードされるのを待つ
waitForPageToLoad [ timeout ] [ ]ページがリロードされるのを待つ
waitForTextPresent [text] [ ]設定した文字列が表示されるまで待つ

・ url の書式

url (例)/triangle/ (相対パス

(例)http://127.0.0.1:3000/triangle/絶対パス

・ id の書式
identifier=id属性値またはname属性値 (例/デフォルト)identifier=commit

(または) commit
id=id属性値 (例)id=triangle_a
name=name属性値 (例)name=commit
xpath=xpath表現 (例)xpath=//div[@id=”results”]

(または) //div[@id=”results”]
link=リンクの文字列 (例)link=戻る

・ textの書式

ワイルドカード使用の文字列(* と ?) (例/デフォルト)glob:面積は*
(または) 面積は*
正規表現 (例)regexp:面積は\d+\.\d+ (意味)数字.数字
文字そのもの (例)exact:面積は6.0

・ select の書式


<select name="city">
<option value="1">東京
<option value="2">大阪
<option value="3">名古屋
</select>
label=text (例/デフォルト)label=東京 (または) 東京 (東京を選択)
value=value(例)value=2 (大阪を選択)
index=index値(例)index=2 (名古屋を選択)

・ keycode の書式

keycode (例)a

(例)\49 (キーコード\49は1)

(例)\82 (キーコード\82はU)

・ 〜AndWait の書式
・ waitForPageToLoadの書式
(注意点)リロードしないAjaxなどはタイムアウトとなる

・ timeout の書式

timeout (例/デフォルト)無指定は30秒で指定値を超えるとエラー

(例)60 (60ミリ秒)

(2) Check

コマンド意味
verifyTitle [text] titleを確認する
verifyText [id] [text]要素の文字列を確認する
verifyValue [id] [value]フォーム要素の内容を確認する。(セレクトボックス含む)
verifyElementPresent [id] 要素が存在することを確認する
verifyElementNotPresent [id] 要素が存在しないことを確認する
verifyVisible [id] 要素が存在して見えることを確認する
verifyNotVisible [id] []要素が見えないことを確認する
verifyAttribute [id@属性名] [text]要素の属性を確認する
verifyTable [テーブルのid.行.列] [text]テーブル内のテキストを確認する
verifyForTextPresent [text]表示されているテキストがあることを確認する
verifyTextNotPresent [text]設定した文字列が表示されていないことを確認する

・ verifyText の書式


<div id=”triangle”>
<form>
辺a:<input >
辺b:<input >
辺c:<input >
</form>
</div>
<div id=”results”>
</div>
[id@属性名][text] (例)//div[@id=”triangle”] regexp:辺a

(注意点) 対象要素の中のすべてのテキストが選ばれ評価される。

ここでは”辺a: 辺b: 辺c:”

・ verifyAttribute の書式


<div id="triangle">


</div>
<div id="results">
</div>
[id@属性名][text] (例)//div@id triangle

(注意点) 最初に合致したものが選択される

・ verifyTable の書式


<table>
<tr><th>都市名</th><th>郵便番号</th><th>電話番号</th></th>
<tr><td>長野市</td><td>380-xxxx</td><td>026-xxx-xxxx</td></tr>
<tr><td>松本市</td><td>390-xxxx</td><td>0263-xx-xxxx</td></tr>
<tr><td>上田市</td><td>386-xxxx</td><td>0268-xx-xxxx</td></tr>
</table>
[テーブルのid.行.列] [text] (例)//table.1.0 長野市

(注意点)セルアドレスは行・列ともに0から始まる

<table>
<tr><th>0.0</th><th>0.1</th><th>0.2</th></th>
<tr><td>1.0</td><td>1.1</td><td>1.2</td></tr>
<tr><td>2.0</td><td>2.1</td><td>2.2</td></tr>
<tr><td>3.0</td><td>3.1</td><td>3.2</td></tr>
</table>

複数パターンのテスト | index | Actionmailer