テストの手順
RubyおよびRuby on Railsの特徴の一つにテスト駆動の開発があります。これは最初にテストコードを書いてからソースコードを書いてテストをしていく方法です。「仕様に基づいて動作すると結果はこうなるはずだ」というテストコードを書くことによるメリットは、一度書いておけば繰り返し使えるということ挙げられます。大きなシステムの仕様であればなおさらで、特に仕様変更に対しソースコードを書き直すことによりデグレートを起こしてしまう危険性の検知に多いに役立ちます。
2.テストの手順
2-1.プログラムの仕様
レコードにあるaとbを読み込んでa+bを計算し、結果を表示するというプログラムにしましょう。
2-2.プロジェクトの生成
(1) プロジェクトTest000の生成
(2) 日本語環境の設定
(3) データベースの作成
テストをする場合はProject_testの環境で実施されるのでDBもそれに対応する必要があります。(db:create:allの指定)
NetBeansで[Rakeタスクを実行/デバッグ..]を選択します。
フィルタ(F):
パラメータ(P):
一致するタスク(M): db:create:all
(in D:/Rails_Projects/Test000)
2-3. アプリケーションの作成
(1) scaffoldの利用
NetBeansで[生成..]を選択
ジェネレータ(G): scaffold
モデル名(N): Record
属性ペア(フィールド型)(A): a:string b:string
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/records
exists app/views/layouts/
exists test/functional/
exists test/unit/
create test/unit/helpers/
exists public/stylesheets/
create app/views/records/index.html.erb
create app/views/records/show.html.erb
create app/views/records/new.html.erb
create app/views/records/edit.html.erb
create app/views/layouts/records.html.erb
create public/stylesheets/scaffold.css
create app/controllers/records_controller.rb
create test/functional/records_controller_test.rb
create app/helpers/records_helper.rb
create test/unit/helpers/records_helper_test.rb
route map.resources :records
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/record.rb
create test/unit/record_test.rb
create test/fixtures/records.yml
create db/migrate
create db/migrate/20100225051438_create_records.rb
(2) マイグレーションファイルの実行
NetBeansで[データベースマイグレション]→[現在のバージョンへ]を選択します。
(in D:/Rails_Projects/Test000)
== CreateRecords: migrating ==================================================
-- create_table(:records)
-> 0.1100s
== CreateRecords: migrated (0.1100s) =========================================
(4) 機能の追加
レコードから読み込んだデータaとbを加算し、結果もListに表示させるようにします。
・ indexメソッドの修正
class RecordsController < ApplicationController
# GET /records
# GET /records.xml
def index
@records = Record.all
@records.each do |record|
record[:c] = record.a + record.b
endrespond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @records }
end
end
:
:
end
・ビュープログラムの修正
<h1>Listing records</h1><table>
<tr>
<th>A</th>
<th>B</th>
<th>A+B</th>
</tr><% @records.each do |record| %>
<tr>
<td><%=h record.a %></td>
<td><%=h record.b %></td>
<td><%=h record.c %></td>
<td><%= link_to 'Show', record %></td>
<td><%= link_to 'Edit', edit_record_path(record) %></td>
<td><%= link_to 'Destroy', record, :confirm => 'Are you sure?', :method => :delete %></td>
</tr><% end %>
</table><br /><%= link_to 'New record', new_record_path %>
(5) 生成されたテストプログラムの実行
まずRuby on Railsで生成されたテストプログラムを実行してみましょう。
NetBeansで[テスト]を選択します。
(6) テスト結果の表示
テスト結果がビジュアルに表示されます。ここでは8件のテストを実行しすべて成功となっています。
2-4.テストパターンの作成
(1) テストデータの登録
上記の記述によって3つのデータが、テストのときrecordsテーブルに登録され実行されます。
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.htmlone: # 本来はユニークであれば何でもいいが
# scaffoldがテストパターンの記述の中で
# oneとtwo使用しているため変更できない。
id: 1
a: 3
b: 5two:
id: 2
a: 10.5
b: 9.5data3:
id: 3
a: -5
b: -50.5
(2) 単体テストの登録
require 'test_helper'class RecordTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
endtest "data_len" do
records=Record.find(:all)
assert_equal 3, records.length, "件数が正しくありません" # recordsに3件データがあれば成功
end
end
これで一つのテストパターンとなり、このブロックの中にRuby言語でテスト内容を記述します。
test テストの名前 doend
(3) 機能テストの登録
機能テストはクライアント側に立ってプログラムを実行した結果を評価するという感覚で行います。
赤の部分はindexメソッドにある演算が正しく行われているかをテストしています。
require 'test_helper'class RecordsControllerTest < ActionController::TestCase
test "should get index" do
get :index # indexメソッドを実行
assert_response :success # HTTPステータスが200なら成功
assert_not_nil assigns(:records) # @recordsがnilでないなら成功
endtest "should get new" do
get :new # newメソッドを実行
assert_response :success # HTTPステータスが200なら成功
endtest "should create record" do
assert_difference('Record.count') do # Record件数が1件増えると成功
post :create, :record => { } # createメソッドを実行
endassert_redirected_to record_path(assigns(:record)) # リダイレクト先の検証
endtest "should show record" do
get :show, :id => records(:one).to_param # showメソッドを実行
assert_response :success # HTTPステータスが200なら成功
endtest "should get edit" do
get :edit, :id => records(:one).to_param # editメソッドを実行
assert_response :success # HTTPステータスが200なら成功
endtest "should update record" do
put :update, :id => records(:one).to_param, :record => { } # updateメソッドを実行
assert_redirected_to record_path(assigns(:record)) # リダイレクト先の検証
endtest "should destroy record" do
assert_difference('Record.count', -1) do # Record件数が1件減ると成功
delete :destroy, :id => records(:one).to_param # destroyメソッドを実行
endassert_redirected_to records_path # リダイレクト先の検証
endtest "access index" do
get :index # indexメソッドを実行
assigns(:records).each do |r| # メソッド実行後の@recordsを取得
assert_equal 8.0, r[:c] if r[:id] == 1 # :idが1のとき8.0なら成功
assert_equal 20.0, r[:c] if r[:id] == 2 # :idが2のとき20.0なら成功
assert_equal -55.5, r[:c] if r[:id] == 3 # :idが3のとき-55.5なら成功
end
end
end
・get、post、put、deleteの意味
ここでメソッドを呼ぶときget、post、put、deleteと異なっている理由は、それぞれのメソッドが要求しているインターフェイスの違いによります。詳細は開発編(1)を参照してください。
2-5.テストの実行
NetBeansで[テスト]を選択します。
10個のテスト中1個失敗しています。
Test-unit gem not found, falling back to default test-unit
(in D:/Rails_Projects/Test000)
C:/Ruby/bin/ruby.exe -I"lib;test" -r"C:/Program Files/NetBeans 6.8/ruby2/nb_test_runner.rb"
"C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
"test/unit/helpers/records_helper_test.rb" "test/unit/record_test.rb"
C:/Ruby/bin/ruby.exe -I"lib;test" -r"C:/Program Files/NetBeans 6.8/ruby2/nb_test_runner.rb"
"C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
"test/functional/records_controller_test.rb"1) 失敗:
test_access_index(RecordsControllerTest):<8.0> expected but was <"35">.
/test/functional/records_controller_test.rb:49:in `test_access_index'
/test/functional/records_controller_test.rb:48:in `each'
/test/functional/records_controller_test.rb:48:in `test_access_index'
C:/Ruby/bin/ruby.exe -I"lib;test" -r"C:/Program Files/NetBeans 6.8/ruby2/nb_test_runner.rb"
"C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"1.453 秒で完了しました。
10 個のテスト、1 個の失敗、0 個のエラー
テスト結果の詳細をみると3 + 5 は 8.0 になることを予想しているのに “35”になっていることが分かります。
文字列の足し算(連結)をしているようです。
2-6.プログラムの修正
・indexメソッドの修正
class RecordsController < ApplicationController
# GET /records
# GET /records.xml
def index
@records = Record.all
@records.each do |record|
record[:c] = record.a.to_f + record.b.to_f
endrespond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @records }
end
end
:
:
end
2-7.テストの実行
NetBeansで[テスト]を選択します。
10個のテストをして全て成功しました。
Test-unit gem not found, falling back to default test-unit
(in D:/Rails_Projects/Test000)
C:/Ruby/bin/ruby.exe -I"lib;test" -r"C:/Program Files/NetBeans 6.8/ruby2/nb_test_runner.rb"
"C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
"test/unit/helpers/records_helper_test.rb" "test/unit/record_test.rb"
C:/Ruby/bin/ruby.exe -I"lib;test" -r"C:/Program Files/NetBeans 6.8/ruby2/nb_test_runner.rb"
"C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
"test/functional/records_controller_test.rb"
C:/Ruby/bin/ruby.exe -I"lib;test" -r"C:/Program Files/NetBeans 6.8/ruby2/nb_test_runner.rb"
"C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"1.172 秒で完了しました。
10 個のテスト、0 個の失敗、0 個のエラー