#author("2018-07-04T15:39:08+09:00","default:wikiwriter","wikiwriter") &tag(Railsテスティングガイド); *目次 [#b63ae818] #contents *関連ページ [#l728a547] -[[Rails テスティングガイド | Rails ガイド:https://railsguides.jp/testing.html]]…日本語版サイト -[[Testing Rails Applications — Ruby on Rails Guides:http://guides.rubyonrails.org/testing.html]]…公式サイト。日本語版は情報が古いのでこちらを参考にすること。 *参考情報 [#z8d31c99] * 1 Railsアプリケーションでテストを作成しなければならない理由 [#m7e16995] * 2 テストを導入する [#xe4e9d82] ** 2.1 Rails Sets up for Testing from the Word Go [#j52f7a32] -Railsプロジェクトを作成すると以下のようなフォルダが作成される #pre{{ $ ls -F test controllers/ helpers/ mailers/ system/ test_helper.rb fixtures/ integration/ models/ application_system_test_case.rb }} ** 2.2 The Test Environment [#v67cb360] -testはtest環境で実施される。 -config/database.ymlでテスト用のデータベースが設定できる。 ** 2.3 Rails meets Minitest [#ye73ffcd] -モデルを生成するとテストが自動的に作成される。 #pre{{ $ bin/rails generate model article title:string body:text ... create app/models/article.rb create test/models/article_test.rb create test/fixtures/articles.yml ... }} -test/models/article_test.rbは以下のような内容となる。 #pre{{ require 'test_helper' class ArticleTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end }} -テストメソッド名は以下のどちらでもよい。 #pre{{ test "the truth" do assert true end def test_the_truth assert true end }} -失敗テスト。articleのtitleが設定されていないので以下のテストは失敗する。 #pre{{ test "should not save article without title" do article = Article.new assert_not article.save end }} -実行。本来失敗してほしいのだが成功してしまう。 #pre{{ $ bin/rails test test/models/article_test.rb }} -articleに検証メソッドを追加すると成功する。 #pre{{ class Article < ApplicationRecord validates :title, presence: true end }} ** 2.4 Available Assertions [#fbdc2b74] **2.5 Rails Specific Assertions [#se6208f2] **2.6 A Brief Note About Test Cases [#ib167b69] **2.7 The Rails Test Runner [#seb79b61] -bin/rails testコマンドで全てのテストを実行できる。 -特定のテストやメソッドを実行する場合。 #pre{{ $ bin/rails test test/models/article_test.rb $ bin/rails test test/models/article_test.rb -n test_the_truth $ bin/rails test test/models/article_test.rb:6 #行番号の指定 $ bin/rails test test/controllers #ディレクトリ }} *3 The Test Database [#a221eb97] -テスト用のデータベースが使われる。 -config/database.ymlで定義。 **3.1 Maintaining the test database schema [#cbfed533] -テストを実行するためには現在のデータがデータベースに反映されていることが必要。 -テストヘルパーは保留中のmigrationsが存在しないあかどうかをチェックする。 **3.2 The Low-Down on Fixtures [#q1f10dde] -Railsではフィクスチャと呼ばれる仕組みを利用してテストデータを準備っする。 -test/fixturesディレクトリ以下に存在しYAMLで定義。 #pre{{ # lo & behold! I am a YAML comment! david: name: David Heinemeier Hansson birthday: 1979-10-15 profession: Systems development steve: name: Steve Ross Kellock birthday: 1974-09-27 profession: guy with keyboard }} -関連の定義。 #pre{{ # In fixtures/categories.yml about: name: About # In fixtures/articles.yml first: title: Welcome to Rails! body: Hello world! category: about }} -fixturesのYAMLではERBを使用することもできる。 -テストの中で以下のように使用可能。 #pre{{ # this will return the User object for the fixture named david users(:david) # this will return the property for david called id users(:david).id # one can also access methods available on the User class david = users(:david) david.call(david.partner) }} * 4 Model Testing [#u1bb93a0] -モデルテストはモデルのテストを実行するもの。 -test/modelsディレクトリに作成する。 #pre{{ $ bin/rails generate test_unit:model article title:string body:text create test/models/article_test.rb create test/fixtures/articles.yml }} * 5 System Testing [#ubac64da] -システムテストは、アプリケーションとシステムの相互作用をテストする。 -リアルorヘッドレスブラウザを使用してテスト実行。 -Capybaraを利用する。 -railsではtest/systemディレクトリ以下に作成する。 #pre{{ $ bin/rails generate system_test users }} -以下の内容 #pre{{ require "application_system_test_case" class UsersTest < ApplicationSystemTestCase # test "visiting the index" do # visit users_url # # assert_selector "h1", text: "Users" # end end }} -デフォルトでシステムテストはSeleniumドライバで実行される。 ** 5.1 Changing the default settings [#e0f1f73e] -railsのシステムテストの設定は簡単に変更できる。 -例えばSeleniumからPoltergeistに変更したい場合Gemfileにpoltergeistを追加したあとで、テストファイルを以下のように変更する。 #pre{{ require "test_helper" require "capybara/poltergeist" class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :poltergeist end class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :firefox end class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :headless_chrome end }} **5.2 Screenshot Helper [#x1e3cf99] -ScreenshotHelperはスクリーンショットヘルパーを取得するのを助ける。 -take_screenshotとtake_failed_screenshotが存在。 **5.3 Implementing a system test [#u21cd85c] -システムテストのスケルトンを生成する。 $ bin/rails generate system_test articles -テストファイルの中身。 #pre{{ require "application_system_test_case" class ArticlesTest < ApplicationSystemTestCase test "viewing the index" do visit articles_path assert_selector "h1", text: "Articles" end end }} -テストの実行。デフォルトでrails testではシステムテストを実行しないのに注意。 bin/rails test:system ★chromedriverが存在しないと実行できない。macOSの場合「brew cask install chromedriver」でインストール可能。 -新しい記事を作成するテスト。 #pre{{ test "creating an article" do visit articles_path click_on "New Article" fill_in "Title", with: "Creating an Article" fill_in "Body", with: "Created this article successfully!" click_on "Create Article" assert_text "Creating an Article" end }} -最初にarticles_pathに移動して、"New Article"ボタンをクリック。そしてタイトルとボディを埋めて保存する。 -システムテストはユーザーが利用しているソフトをシステムをテストする実情に最も近いテストとなる。 * 6 Integration Testing [#kb7fa84e] -統合テストはアプリケーションのさまざまな箇所が相互作用するさまをテストする。 -アプケーション内の重要なワークフローをテストする。 -railsでは統合テストはtest/integrationディレクトリに作成される。 -以下のように作成できる。 #pre{{ $ bin/rails generate integration_test user_flows }} -その中身。 #pre{{ require 'test_helper' class UserFlowsTest < ActionDispatch::IntegrationTest # test "the truth" do # assert true # end end }} -テストはActionDispatch::IntegrationTestを警鐘する。 ** 6.1 Helpers Available for Integration Tests [#r6b1a798] -ActionDispatch::IntegrationTestでは標準のテストに加え追加のヘルパーが使用できる。 --ActionDispatch::Integration::Runner --ActionDispatch::Integration::RequestHelpers --ActionDispatch::Integration::Session **6.2 Implementing an integration test [#a5bd52de] -ブログシステムに統合テストを追加する。 $ bin/rails generate integration_test blog_flow -BlogFlowTestを実装する。"/"を取得しh1タグの中身が"Welcome#index"であることを確認。なおこのテストを実行するにはwelcome_controllerを先に作っておかないと行けない(後述)。 #pre{{ require 'test_helper' class BlogFlowTest < ActionDispatch::IntegrationTest test "can see the welcome page" do get "/" assert_select "h1", "Welcome#index" end end }} -welcome_controllerの作成。 bundle exec rails generate controller Welcome index -routes.rbの設定。 #pre{{ Rails.application.routes.draw do get 'welcome/index' root 'welcome#index' resources :articles end }} -記事作成のテスト。 #pre{{ test "can create an article" do get "/articles/new" assert_response :success post "/articles", params: { article: { title: "can create", body: "article successfully." } } assert_response :redirect follow_redirect! assert_response :success assert_select "p", "Title:\n can create" # assert_select "p" do |element| # # 該当するNokogiri::XML::NodeSetがかえってくる(この場合3つの"p"要素のNokogiri::XML::Elementを含む) # # textでタグを除いた状態のテキストが取得できる。これとの比較になる。 # p element.text # end end }} * 7 Functional Tests for Your Controllers [#fa363cc5] -Railsではコントローラーの個別の(?)メソッドをテストするにはfunctional test(機能テスト)を使用する。 **7.1 What to include in your Functional Tests [#sb6d18bf] -以下の内容を機能テストに記述する --リクエストが成功したか --リダイレクトが正しいか。 --ユーザー認証が成功したか。 --正しいオブジェクトがtemplateに埋め込まれたか。 --適切なメッセージがビューに表示されたか。 -機能テストを作成するにはscaffoldを使用するのが簡単。test/controllers/articles_controller_test.rbがそれ。 $ bin/rails generate scaffold_controller article title:string -すでにコントローラーを作成済みで、7つのデフォルトアクションに対するテストを作成したい場合以下のように実行する。 $ bin/rails generate test_unit:scaffold article -テストの一つ。 #pre{{ # articles_controller_test.rb class ArticlesControllerTest < ActionDispatch::IntegrationTest test "should get index" do get articles_url assert_response :success end end }} -getメソッドwebリクエストを送信し、@responseで結果を受ける。以下のパラメータを受け取る。 --URI(例えばarticles_url)。 --params --headers --env --xhr --as -showアクションでリファラを設定する場合。 #pre{{ get article_url, params: { id: 12 }, headers: { "HTTP_REFERER" => "http://example.com/home" } }} -updateアクションをAjaxリクエストする場合。 #pre{{ patch article_url, params: { id: 12 }, xhr: true }} -記事作成メソッドのテスト(この前にテストを実行すると、新たに追加したvalidationにより失敗するとあるがデフォルト状態でも作成できそうだが…)。 #pre{{ test "should create article" do assert_difference('Article.count') do post articles_url, params: { article: { body: 'Rails is awesome!', title: 'Hello Rails' } } end assert_redirected_to article_path(Article.last) end }} **2.2 Railsを即座にテスト用に設定する [#qb174f1a] -プロジェクトを作成すると、以下のフォルダが自動的に作成される。 #pre{{ $ ls -F test controllers/ helpers/ mailers/ test_helper.rb fixtures/ integration/ models/ }} **2.3 フィクスチャのしくみ [#e38e1008] -フィクスチャ=サンプルデータ。 -YAMLで記述。test/fixtures以下。 #pre{{ david: name: David Heinemeier Hansson birthday: 1979-10-15 profession: Systems development steve: name: Steve Ross Kellock birthday: 1974-09-27 profession: guy with keyboard }} -YAMLはERBで処理される。 -フィクスチャはActive Recordオブジェクト。 #pre{{ # davidという名前のフィクスチャに対応するUserオブジェクトを返す users(:david) # idで呼び出されたdavidのプロパティを返す users(:david).id # Userクラスで利用可能なメソッドにアクセスすることもできる email(david.girlfriend.email, david.location_tonight) }} -フィクスチャとして容易したymlファイルはテストの実行前にテストDBにロードされる。 *3 モデルに対する単体テスト [#c65fc1b9] -articleモデルを生成。 #pre{{ $ bin/rails generate scaffold article title:string body:text }} -以下のようなテストクラスが生成される。 #pre{{ require 'test_helper' class ArticleTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end }} **3.1 テストデータベースのスキーマを管理する [#re44c079] **3.2 テストを実行する。 [#pfc34540] -以下のように実行できる。 #pre{{ bin/rails test test/models/article_test.rb }} -特定のメソッドdけをテスト。 #pre{{ bin/rails test test/models/article_test.rb test_the_truth }} -失敗のテスト。article.rbを変更。 #pre{{ class Article < ActiveRecord::Base validates :title, presence: true end }} -テスト追加。 #pre{{ class ArticleTest < ActiveSupport::TestCase test "the truth" do assert true end test "should not save article without title" do article = Article.new assert_not article.save, "Saved the article without a title" end end }} **3.3 単体テストに含めるべき項目 [#j3ce5ae7] **3.4 利用可能なアサーション [#g83e6cdb] **3.5 Rails固有のアサーション [#y9342428] *4 コントローラの機能テスト [#t3c058fd] -1つのコントローラーに含まれる複数のアクションをテスト。 -機能テスト=functional test。 **4.1 機能テストに含める項目 [#y660cd93] -以下の項目を含める --Webリクエストが成功したか --正しいページにリダイレクトされたか --ユーザー認証が成功したか --レスポンスのテンプレートに正しいオブジェクトが保存されたか --ビューに表示されたメッセージは適切か -test/controllers/articles_controller_test.rb #pre{{ test "should get new" do get new_article_url assert_response :success end }} -showアクションに対するテストの場合。 #pre{{ test "should show article" do get article_url(@article) assert_response :success end }}