RSpec/Capybara -- はじめの一歩
2013/08/15
連載第2回目は、プログラマーの古き良き伝統「Hello World」です。RailsアプリケーションのTopページに「Hello World!」というコンテンツを持つ p
要素が存在するかどうかをRSpecとCapybaraでテストします。
本連載のメインの読者としてはRubyとRailsを学習中の方を想定しています。したがって、RubyとRailsはインストール済みであるという前提で話を始めます。Ruby のバージョンは2.0.0で、Railsのバージョンは4.0.0です。オブジェクト、クラス、モジュール、メソッド、インスタンス変数といったRubyの基本的な概念、モデル、ビュー、コントローラ、ルーティングといったRailsの基本的な概念については説明しません。なお、データベース管理システムとしてはMySQLを使用します。おそらく、SQlite3やPostgreSQLやOracleでもうまく行くと思いますが、動作確認はしません。もし動かないケースが見つかりましたら、ご連絡ください。
Railsアプリケーションの作成
では、まずサンプルアプリケーションを作りましょう。名前は、ギリシャの女神の名前を取って sinope
とします。
$ rails new sinope -d mysql $ cd sinope $ rake db:create $ rake db:migrate $ rake db:test:prepare
まだマイグレーションスクリプトが存在しないのに rake db:migrate
コマンドを実行したのは、db/schema.rb
ファイルを生成するためです。次の、rake db:test:prepare
コマンドは、db/schema.rb
ファイルを読み取ってテスト環境のためのデータベーススキーマを構築します。
RSpec と Capybara のインストール
次に、RSpec と Capybara をインストールします。
Gemfile
の末尾に以下のコードを追加します。
group :test do gem 'rspec-rails' gem 'capybara' end
追加された Gem パッケージをインストールします。
$ bundle
bin
ディレクトリの下に rspec
プログラムを設置します。
$ bundle binstubs rspec-core
続いて、次のコマンドを実行します。
$ rails g rspec:install
このコマンドにより spec
ディレクトリが作られ、その下に spec_helper.rb
というファイルが生成されます。RSpec の挙動を設定する重要なファイルです。
$ rm -rf test
test
ディレクトリ以下は不要なので消しておきます。
Railsジェネレータの設定
rails g
コマンドでモデルやコントローラを作成したときに、同時にRSpecのファイルも生成されるように設定します。
config/application.rb
を次のように編集します。
require File.expand_path('../boot', __FILE__) require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(:default, Rails.env) module Sinope class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de config.generators do |g| g.test_framework = "rspec" end end end
config.generators do
以下の3行を挿入しました。テストフレームワークとして RSpec を使うように設定しています。
筆者の場合は、さらに次のように設定しています。
config.generators do |g| g.test_framework = "rspec" g.controller_specs = false g.helper_specs = false g.view_specs = false end
私はコントローラ、ヘルパー、ビューのためのテストをほとんど書かないので、デフォルトでは生成しないようにしています。これらの設定は、各自の方針によって取捨選択してください。
私がこれらのテストをあまり書かない理由は、いずれ説明します。
トップページの生成
トップページを表示するための top#index
アクションを作ります。
$ rails g controller top index $ rails s
config/routes.rb
を編集します。
Sinope::Application.routes.draw do root to: 'top#index' end
ブラウザで http://localhost:3000/
を開くと、右のような画面になります。
最初のテスト
いよいよ本題です。最初のテストを書きましょう。まず、spec/features
ディレクトリを作ります。
$ mkdir spec/features
その下に top_page_spec.rb
という新規ファイルを次のような内容で作成します。
require 'spec_helper' describe 'トップページ' do specify '挨拶文を表示' do visit root_path expect(page).to have_css('p', text: 'Hello World!') end end
このコードの意味について次回説明します。トップページの中に、中身が「Hello World!」であるような p
要素があるかどうかを調べています。
テストを実行します。
$ bin/rspec
すると20行ほどのエラーメッセージが出力されます。その中に次のような箇所があることを確認してください。
Failures: 1) トップページ 挨拶文を表示 Failure/Error: expect(page).to have_css('p', text: 'Hello World!') Capybara::ExpectationNotMet: expected to find css "p" with text "Hello World!" but there were no matches... # ./spec/features/top_page_spec.rb:6:in `block (2 levels) in <top (required)>'
そして、app/views/top/index.html.erb
を次のように修正します。
<h1>Top#index</h1> <p>Hello World!</p>
再度、bin/rspec
コマンドでテストを実行してください。今度は、エラーメッセージが出ないはずです。メッセージの中に次のような箇所がありますね。
1 example, 0 failures
失敗が 0 個。これがテスト成功の証です。
次回は
今回できなかったテストコードの説明を書く予定です。では、また。
[更新] 次回の話と整合性を取るため、テストコード中の feature
を describe
に、scenario
を specify
に変更しました。また、テストを実行するコマンドを rake
から bin/rspec
に変更しました。(2013/08/16)
[更新] rake db:migrate
コマンドの後に、rake db:test:prepare
コマンドを実行する手順を加えました。(2013/08/18)
[更新] 「Railsジェネレータの設定」の項で、編集対象ファイルのパスが間違っていました。app/application.rb
ではなく config/application.rb
が正しいです。読者の方からご指摘をいただきました。ありがとうございます。(2013/08/28)