テスト(test)

テストとは

説明

  • あるURLにアクセスした際に、予期した画面が表示されるか
  • ある正しい操作をした際に、アプリケーションの状態が正しく変更されるか
  • ある正しくない操作をした際に、適切なエラーメッセージが表示されるか

単体テスト

  • モデルの検索系メソッドが正しい値を取得できるか
  • モデルの更新系メソッドが正しくデータベースを更新できるか
  • モデルの更新系メソッドが不正な入力に対して、適切なエラーを発生させるか

機能テスト

  • 適切なテンプレートが選択されているか
  • インスタンス変数に適切な値が格納されているか
  • 適切にレンダリングされているか
  • 更新系のアクションが正しくデータベースを更新されるか

総合テスト

  • ログインして、新しいメンバーを追加して、ログアウトするといった一連の動きをテスト

Railsのテストについて

Railsのテストの仕組み

  1. ユニットテスト
  2. ファンクションテスト
  3. インテグレーションテスト

ユニットテスト

モデル対処にテストを行う

ファンクションテスト

モデルからビュー、コントローラまで含む、アクションごとのテストを行う

インテグレーションテスト

アクション間をまたぐテストなどを行う

テストを実行

説明

Railsではテストの実行の仕組みは2つある

  1. rubyコマンドで直接実行
  2. rakeコマンドで実行

rubyコマンドで直接実行

$ ruby test/unit/entry_test.rb

rakeコマンドで実行

タスク説明
rake db:test:preparedevelopment環境のDBからスキーマをコピーするなど、テスト用のDBを準備する
rake testすべてのテストを実行
rake test:functionalsファンクショナルテストを実行
rake test:integrationインテグレーションテストを実行
rake test:unitsユニットテストを実行
rake test:recentファイルのタイムスタンプをもとに、10分以内に更新されたファイルのテストを実行

テストデータ (fixtures)

説明

事前に用意したテストデータを読み込み、常にDBの内容を一定に保つための仕組みのことを、フィクスチャと呼ぶ

フィクスチャを用意

test/fixtures/テーブル名.yml
rubyonrails:
  id: 1
  name: Ruby on Rails
  url: http://www.rubyonrails.org
 
google:
  id: 2
  ;name: Google
  url: http://www.google.com

テスト内からフィクスチャを読み込む

require 'test_helper'

class WebSiteTest < ActiveSupport::TestCase
  test "web_site_count" do
    assert_equal 2, WebSite.count
  end
end

フィクスチャを使用

require 'test_helper'
 
class SiteTest < ActiveSupport::TestCase
  fixtures :sites
 
  def test_google_fixture
    # フィクスチャ名を指定して使用
    google = sites(:google)
    assert_equal "http://www.google.com", google.url
  end
 
  def test_google_fixture_from_db
    # findメソッドなどでDBからロードして使用
    google = Site.find(2)
 
    # フィクスチャ名で取得したものと同じであることを検証
    assert_equal sites(:google), google.url
  end
end

フィクスチャからのデータの取得

フィクスチャに含まれているデータはテストの実行時に使うものだがmこれを使ってデータをロード

  • 開発用データ用のディレクトリの作成
$ mkdir db/migrate/dev_data
  • YAMLファイルの作成
  • マイグレーションファイルの作成
$ ruby script/generate migration <マイグレーション名>
  • マイグレーションファイルの編集
require 'active_recode/fixtures'
class <クラス名> < ActiveRecode::Migration
  def self.up
    down
 
    directory = File.join(File.dirname(__FILE__), 'dwv_data')
    Fixtures.create_fixtures(disrectory, "<YAML名>")
  end
  def self.down
    <YAML名>.delete_all
  end
end

ユニットテストについて

使い方

#coding: utf-8
require 'test_helper'

class ArticleTest < ActiveSupport::TestCase
test テスト名 do
テストコード
end

class ShopTest < ActiveSupport::TestCase
  def test_instanciate_from_cvs_string
    shop = Ship.parse("コーヒー, aaa")
    assert_not_nil shop
    assert_equal "コーヒー", shop.name
    assert_equal "aaa", shop.tel
  end
end
class Shop < ActiveRecord::Base
  def self.parse(cvs_str)
  end
end
def self.parse(cvs_str)
  params = cvs_str.split(/\s*, \s*/)
  Shop.new(:name => params[0], :tel => params[1])
end

ファンクショナルテスト

単一のアクションに対して、モデル・ビュー・コントローラを結合してテスト

requite File.dirname(__FILE__) + '/../test_helper'
 
class EntriesControllerTest < ActionController::TestCase
  def test_truth
    assert true
  end
end

流れ

テスト環境をセットアップ
requite File.dirname(__FILE__) + '/../test_helper'
コントローラを指定
requite File.dirname(__FILE__) + '/../test_helper'
 
class ShopsControllerTest < Test::Unit**testCase
  def setup
    @controller = ShopsController.new
    @request = ActionController::TestRequest.new
    @response = ActionController:TestResponse.new
  end
end
リクエストを送信
def test_should_get_index
  get :index
end
アクションの実行結果を確認
レスポンスが成功したかを検証
assert_response :success
アクション内で設定されたインスタンス変数を検証
assigns
出力結果のHTMLを検証
assert_select

テストメソッド

リクエスト送信のためのメソッド
メソッド説明
get(action, parameters)アクションに対して、GETリクエストを送信
post(action, parameters)アクションに対して、POSTリクエストを送信
xhr(request_method, action, parameters = nil, session = nil, flash = nil)アクションに対して、XMLHTTPRequestを送
状態設定・取得のためのメソッド
メソッド説明
assigns(key = nil)アクションを実行した結果、インスタンス変数に代入されたオブジェクトを取得
sessionファンクショナルテストで使用されるセッションへのアクセサ
flashコントローラ内で使用するflashへのアクセサ
検証のためのメソッド
メソッド説明
assert_response(type, message = nil)アクション実行結果のレスポンスコードを検証
assert_redirected_to(options = {}, message = nil)リダイレクトを返すアクションに対して、そのリダイレクト先がどうなっているか検証
assert_template(expected, message = nil)そのアクションで指定されたテンプレートが描写されているかを検証
assert_select(selector, equality?, message?)アクション実行の結果として描写されるHTMLの内容を検証

インテグレーションテスト

説明

複数のアクションやコントローラにまたがる挙動を検証するためのテスト

テストを生成

$ rails generate integration_test テスト名

流れ

  1. テスト環境をセットアップ
  2. リクエストとその検証、というペアを複数回記述

テストを記述

  • /shops/listに店の一覧がある
    • 新規追加画面に店を追加するためのフォームがある
  • /shops/newに店を追加するためのフォームがある
    • フォームのアクションは/shops/createである
    • shopの店名を入力するためのフォームがある
  • shop[name]を指定し、/shops/createにPOSTリクエストを送る
  • shopの件数が増えていることを検証
class CreateNewShopFinallyShowThemAllTest < AxtionController::IntegrationTest
  fixtures :users, :shops
 
  def test_create_new_shop_and_show_thwm_all
    shops_count_before_create = Shop.count
 
    get "/shops/list"
    assert_response :success
    assert_select "table > tr", :count => (shops_count_before_create + 1)
    assert_select "a[href=?]", %r!/shops/new!
 
    get "/shops/new"
    assert_response :success
    assert_select "form[action=?]", %r!/shops/create!
    assert_select "form input[name='shop[name]']"
 
    post_via_redirect "/shops/create", :shops => { :name => "new_shop" }
    assert_response :seccess
    assert_template "shops/list"
 
    assert_equal (shops_count_before_create +1), Shop.count
  end
end

ユニットテストで使うメソッド

テストメソッド

メソッド説明
assert(式 [, メッセージ])式が真ならば成功
assert_equal(変数1, 変数2 [, メッセージ])変数1と変数2が等しければ成功
assert_not_equal(変数1, 変数2 [, メッセージ])変数1と変数2が等しくなければ成功
assert_nil(変数 [, メッセージ])変数がnilならば成功
assert_not_nil(変数 [, メッセージ])変数がnilじゃなければ成功
assert_match(正規表現, 文字列 [, メッセージ])正規表現に文字列がマッチすれば成功
assert_no_match(正規表現, 文字列 [, メッセージ])正規表現に文字列がマッチしなければ成功
assert_raise(例外1, 例外2 [, 例外3...]) { }ブロックを実行して例外1,2が発生し、その例外がexpected_exception_klassクラスならば成功
assert_nothing_raised(例外1, 例外2 [, 例外3...]) { .. }ブロックを実行して例外1,2がおきなけらば成功
assert_in_delta(expected_float, actual_float, delta, message="")
flunk([メッセージ])常に失敗
未定義のテストケースなどを暫定的に失敗させたりする場合に利用
assert_difference(expressions, difference = 1, message = nil, 6block)ブロック実行後にecpressionsの値がdifferenceの分だけ変わっていれば成功
assert_no_difference(exoressions, message = nil, &block) ブロック実行前後でexpressionsの値が変わっていなければ成功