RailsのテストフレームワークRSpecの基礎知識
実践Ruby on Rails 4 現場のプロから学ぶ本格Webプログラミング
顧客管理システムの構築を体験しながら、Railsアプリケーション開発のノウハウを習得! この記事は、書籍『実践Ruby on Rails 4 現場のプロから学ぶ本格Webプログラミング』の内容を、Think IT向けに特別にオンラインで公開しているものです。詳しくは記事末尾の書籍紹介欄をご覧ください。RSpecの基礎知識
本記事では、テストフレームワークとしてRSpecを採用します。RSpecをうまく活用すると、簡潔で読みやすいテストコードを書くことができ、Railsアプリケーションの保守性を高めることができます。
しかし、RSpecの用語法や表記法はやや独特で、慣れるまでには時間がかかります。読者の中にはとまどいを覚える方がいらっしゃるかもしれませんが、次章以降を読み進めるうえでの鍵となりますので、是非じっくりと読んで理解してください。
テストとは
Webアプリケーション開発の文脈において、テストという言葉はさまざまな意味で用いられます。日常的な場面では、人がWebアプリケーションの動きを目視でチェックする作業を意味します。たとえば、Webアプリケーションをサーバーコンピュータにインストールし、人が実際にWebブラウザを操作して、仕様どおりの反応を返すかどうか確かめるといった作業です。
しかし、プログラマの間では「テスト」という言葉がしばしば異なる意味で用いられます。私たちは、専用のプログラムによってWebアプリケーションの動作を確認することを「テスト」と呼びます。この意味でのテストは自動で行われます。人間がディスプレイを見守っていなくてもテストが進行し、テストが終わると成功あるいは失敗という結果がディスプレイに表示されます。
本書では「テスト」という言葉を、ソフトウェアによって自動で実施されるテストという意味で用います。
テストを実行するための専用のプログラムを「テスト」と呼ぶ用法もあります。たとえば、私たちはしばしば「テストを書く」という言い方をします。これは、テストを実行するためのプログラムを作ることを意味します。
RSpecとは
前著『改訂新版 基礎Ruby on Rails』では、Railsに標準で組み込まれているテストフレームワークTest::Unitを用いたテストについて解説しましたが、本書ではRSpec(アールスペック)という別のテストフレームワークを採用することにします。
Rails 4では標準のテストフレームワークがTest::UnitからMiniTestに変更されました。MiniTestはTest::Unitの機能強化版で、Test::Unitとの互換性をほぼ保っています。
RSpecを採用した理由は、正直に言えば「私が普段使っているから」ということになります。RSpecはRailsプログラマの間で高い人気を獲得していますが、その独特の用語法や書き方になじめない方も多いようです。私はRSpecにはTest::Unitやその後継のMiniTestにはない優れた特徴があると考えています。
しかし、RSpecがRailsに組み込まれていないことからもわかるように、けっして「事実上の標準(de facto standard)」の地位をRails業界において確立しているわけではありません。
RSpecの初期設定
RailsでRSpecを利用する場合、一度だけ次のコマンドを実行する必要があります。
$ bin/rails g rspec:install
ゲストOSで実行してください。すると、specディレクトリが作られて、その下にspec_helper.rbというファイルが生成されます。初期状態での内容は次のとおりです(コメント行を省略しています)。
spec/spec_helper.rb
ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration) RSpec.configure do |config| config.fixture_path = "#{::Rails.root}/spec/fixtures" config.use_transactional_fixtures = true config.order = "random" end
Rails 4.1に対応するため、このファイルの7行目を次のように書き換えてください。
ActiveRecord::Migration.maintain_test_schema!
RSpec ―― はじめの一歩
RSpecがどんなものであるかを感覚的に理解するため、実際にRSpecによる簡単なテストコードを書いて、実行してみることにしましょう。
Baukisのプロジェクトディレクトリ直下にspecディレクトリがあります。その下にexperimentsというサブディレクトリを作り、string_spec.rbというファイルを作成してください。
spec/experiments/string_spec.rb
require 'spec_helper' describe String do describe '#<<' do example '文字の追加' do s = "ABC" s << "D" expect(s.size).to eq(4) end end end
RSpecのテストコードは、通常specディレクトリの下に置きます。ファイル名の末尾は_spec.rbで終わるようにしてください。これらのファイルをspecファイルと呼びます。
specファイルはspecディレクトリのサブディレクトリに適宜分類して配置します。どのサブディレクトリにどんなspecファイルを置くかは慣習的に決まっています。たとえば、モデルクラスに関するspecファイルはspec/modelsディレクトリに、APIに関するspecファイルはspec/requestsディレクトリに置くのが一般的です。しかし、独自のサブディレクトリを用意しても構いません。ここでは、RubyもしくはRailsの仕様に関する実験を行うspecファイルを置く場所としてexperimentsサブディレクトリを作成しました。これは本書独自のルールです。
テストコードの本体は次の3行です。
s = "ABC" s << "D" expect(s.size).to eq(4)
まず変数sに"ABC"という文字列をセットし、それに"D"という文字を追加しています。最後に、expectメソッドで変数sの状態を調べています。expectメソッドの使い方は後述しますが、ここではsの長さが4であるかどうかをチェックしています。
では、このspecファイルを実行してみましょう。ゲストOSのターミナルで、次のコマンドを実行してください。
$ bin/rspec spec/experiments/string_spec.rb
すると、次のような結果がターミナルに表示されます。
. Finished in 0.13482 seconds 1 example, 0 failures Randomized with seed 15657
ただし、3行目の「0.13482」および6行目の「15657」は、実行するたびに値が変化します。この結果の読み方については、後述します。
bin/rspecコマンドの結果の最終行に出力される「Randomized with seed ...」という行は、RSpecが内部的に利用している乱数のシード値(疑似乱数を計算するための係数)を表しています。RSpecは複数のエグザンプルをランダムな順番で実行するために乱数を利用しています。これ以降、テストの結果を掲載する際にはこの行を省略します。
このようにbin/rspecコマンドはspecファイルのパスを指定して個別に実行することも可能ですが、specファイルを含むディレクトリを指定して、そこに含まれるspecファイルを一括して実行することもできます。たとえば、次のコマンドはspecディレクトリ以下にあるすべてのspecファイルを実行します。
$ bin/rspec spec