*目次 [#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

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS

アークウェブのサービスやソリューションはこちら