テストの手順

[8]テスト
1.テスト駆動開発
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メソッドの修正


/app/controllers/records_controller.rb
class RecordsController < ApplicationController
# GET /records
# GET /records.xml
def index
@records = Record.all
@records.each do |record|
record[:c] = record.a + record.b
end

respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @records }
end
end
  :
  :
end



・ビュープログラムの修正


/app/views/records/index.html.erb
<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) テストデータの登録


/test/fixtures/records.yml
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html

one: # 本来はユニークであれば何でもいいが
# scaffoldがテストパターンの記述の中で
# oneとtwo使用しているため変更できない。
id: 1
a: 3
b: 5

two:
id: 2
a: 10.5
b: 9.5

data3:
id: 3
a: -5
b: -50.5

上記の記述によって3つのデータが、テストのときrecordsテーブルに登録され実行されます。

(2) 単体テストの登録


/test/unit/record_test.rb
require 'test_helper'

class RecordTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end

test "data_len" do
records=Record.find(:all)
assert_equal 3, records.length, "件数が正しくありません" # recordsに3件データがあれば成功
end
end




test テストの名前 do

end

これで一つのテストパターンとなり、このブロックの中にRuby言語でテスト内容を記述します。

(3) 機能テストの登録
機能テストはクライアント側に立ってプログラムを実行した結果を評価するという感覚で行います。


/test/functional/records_controller_test.rb
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でないなら成功
end

test "should get new" do
get :new # newメソッドを実行
assert_response :success # HTTPステータスが200なら成功
end

test "should create record" do
assert_difference('Record.count') do # Record件数が1件増えると成功
post :create, :record => { } # createメソッドを実行
end

assert_redirected_to record_path(assigns(:record)) # リダイレクト先の検証
end

test "should show record" do
get :show, :id => records(:one).to_param # showメソッドを実行
assert_response :success # HTTPステータスが200なら成功
end

test "should get edit" do
get :edit, :id => records(:one).to_param # editメソッドを実行
assert_response :success # HTTPステータスが200なら成功
end

test "should update record" do
put :update, :id => records(:one).to_param, :record => { } # updateメソッドを実行
assert_redirected_to record_path(assigns(:record)) # リダイレクト先の検証
end

test "should destroy record" do
assert_difference('Record.count', -1) do # Record件数が1件減ると成功
delete :destroy, :id => records(:one).to_param # destroyメソッドを実行
end

assert_redirected_to records_path # リダイレクト先の検証
end

test "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

赤の部分はindexメソッドにある演算が正しく行われているかをテストしています。

・get、post、put、deleteの意味
ここでメソッドを呼ぶときget、post、put、deleteと異なっている理由は、それぞれのメソッドが要求しているインターフェイスの違いによります。詳細は開発編(1)を参照してください。

2-5.テストの実行
NetBeansで[テスト]を選択します。


実行結果
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 個のエラー

10個のテスト中1個失敗しています。
テスト結果の詳細をみると3 + 5 は 8.0 になることを予想しているのに “35”になっていることが分かります。
文字列の足し算(連結)をしているようです。

2-6.プログラムの修正
・indexメソッドの修正


/app/controllers/records_controller.rb
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
end

respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @records }
end
end
  :
  :
end

2-7.テストの実行
NetBeansで[テスト]を選択します。


実行結果
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 個のエラー

10個のテストをして全て成功しました。



ActiveScaffold | index | テストで使うメソッド