- 追加された行はこの色です。
- 削除された行はこの色です。
*目次 [#q1036b05]
#contents
*Railsによるテスト作成 [#yb95687b]
http://www.pragmaticprogrammer.com/title/rails/
の12章「Task T: Testing」と
http://jp.rubyist.net/magazine/?0013-RubyOnRails
を参照しながらRailsによるユニットテスト、機能テスト、自動化テストの作成を行ってみる
**準備 [#l95a796f]
スケルトンを作る
# rails gentest
この段階でgentest/test/にはユニットテスト、機能テストのスケルトンも作成されている
# cd gentest/test
# dir
fixtures/
functional/
mocks/
unit/
test_helper.rb
fixturesはテスト用データベースの初期化時に初期データとして投入するデータを定義したYAML(*.yml)ファイルを格納するディレクトリ、functionalは機能テストを格納するディレクトリ、mocksはモックを格納するディレクトリ、unitはユニットテストを格納するディレクトリになる。test_helper.rbはテスト用の共通関数、定義置き場。
**モデル定義とテスト作成 [#u7932361]
モデルを定義して、テストを作成する。
***準備 [#a90f347e]
DBテーブルは下記を使う(テーブル名、カラム名はRailsの規約に従う)
-- books
create table books (
id integer primary key,
title varchar(255) not null,
description text,
updated_at datetime
);
このテーブルスキーマをdb/schema.sqlとして保存し、下記でデータベースを作成する(SQLiteを使用)
# cd db
# sqlite3 gentest.db < schema.sql
接続情報をconfig/database.ymlに記載する
development:
adapter: sqlite3
dbfile: db/gentest.db
モデルクラス(Book)のスケルトンを作成する
# ruby script/generate model Book
この段階で、
test/unit/book_test.rb
test/fixtures/books.yml
が自動作成される
book_test.rbはBookクラス用のユニットテスト、books.ymlはBookモデル用のfixtureになる。
***最初のテスト実行 [#tfb0883a]
test/unit/book_test.rbは下記のようになっている
require File.dirname(__FILE__) + '/../test_helper'
class BookTest < Test::Unit::TestCase
fixtures :books
# Replace this with your real tests.
def test_truth
assert_kind_of Book, books(:first)
end
end
RailsのテストクラスはTest::Unit::TestCaseクラスのサブクラスになっている。[[Test::Unitフレームワーク>http://www.ruby-lang.org/ja/man/?cmd=view;name=Test%3A%3AUnit]]はRailsにバンドルされているので、この段階ですぐにテスト実行してみることができる。
# ruby test/unit/book_test.rb
Railsはtestスクリプトを実行するたびに、テストデータベースを作成し、テストメソッドを実行するたびにfixtureのデータでテストデータベースのデータを初期化する。
しかし、まだテストデータべースにdb/gentest.dbのスキーマを定義していないので、この検査は失敗する。
テストデータベースのスキーマ定義は下記のrakeコマンドによって実行する
# rake clone_structure_to_test
これで、スキーマだけがテストデータベースに定義される・・・はずなのだが、自分の環境では下記のエラーを吐いて失敗する
rake aborted!
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.[]
ちょっと調べてみたが、原因はまだ不明。
ので、以下は実際に動作確認なしの情報になる
***fixture定義 [#z20f23a3]
スケルトン状態ではtest/fixtures/books.ymlの内容は下記の通り
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
first:
id: 1
another:
id: 2
idだけがデータセットされている状態。
fixtureとして下記を記述する
first:
id: 1
title: 基礎からはじめるRuby
description: 基礎からはじめるRubyの説明
second:
id: 2
title: Effective Java
desctiption: 〜〜〜〜〜〜〜
***モデルオブジェクト作成とレコード読み込みのテスト [#m1b5a227]
test/unit/book_test.rbにsetup()、test_create()メソッドを下記のように定義する~
(Test::Unitはtest_で始まるメソッドを全て自動実行する。またsetup()メソッドは各テストメソッドが呼ばれる前に必ず実行される)
def setup
@book = Book.find(1)
end
def test_create
assert_kind_of Book, @book
assert_equal 1, @book.id
assert_equal "基礎からはじめるRuby", @book.title
assert_equal "基礎からはじめるRubyの説明", @book.description
end
setup()メソッドではidが1のBookレコードを@bookに格納し、各テストメソッドで参照できるようにしている。
test_create()メソッドではまず、@bookがBookモデルのオブジェクトであることを確認し、その後オブジェクトのid、title、descriptonが正しくセットされていることを確認している。
***レコード更新のテスト [#sfd65f00]
test/unit/book_test.rbにtest_update()メソッドを下記のように定義する。
def test_update
assert_equal "基礎からはじめるRuby", @book.title
@book.title = "新・基礎からはじめるRuby";
assert @book.save @book.errors.full_messages.join("; ")
@book.reload
assert_equal "新・基礎からはじめるRuby", @book.title
end
assertメソッドでテストデータベースへの更新が正しく行われることをチェックし、その後reload()メソッドで@bookの状態を更新したら、正しく更新されたことを確認している
***レコード削除のテスト [#wc379dfa]
test/unit/book_test.rbにtest_destroy()メソッドを下記のように定義する。
def test_destroy
@book.destroy
assert_raise(ActiveRecord::RecordNotFound) { Book.find(@book.id) }
end
レコードを削除した後、そのレコードを検索するとActiveRecord::RecordNotFoundのExceptionが発生することをassert_raiseメソッドでチェックしている
***DRYの導入 [#xddd8c8d]
books.ymlに定義した値(基礎からはじめるRuby等)をテストコード中にまた記述してしまうのはDRY(Don't Repeat Yourself)に反する。
フレキシビリティを保ちつつ、テストコードを書くには下記のようにする
def test_create
assert_kind_of Book, @book
# fixture名を指定して取り出すことができる(@bookではなく@booksであることに注意)
first_book = @books["first"]
assert_equal first_book["id"], @book.id
assert_equal first_book["title"], @book.title
assert_equal first_book["description"], @book.description
end
下記のようにすれば、マッチするfixtureを自動で探して値をとってきてくれるのでより楽。(@fixture名_カラム名)
def test_create
assert_kind_of Book, @book
assert_equal @first_id, @book.id
assert_equal @first_title, @book.title
assert_equal @first_description, @book.description
end