こんにちは、かつコーチです。
「テストを書いたほうがいいのは分かるけど、何から始めればいいか分からない」と感じたことはありませんか。
Rubyの世界で最もよく使われるテストツールがRSpecです。
この記事では、RSpecのインストールから、describe・it・expectという基本構文、実際にテストを実行するところまでを、順を追って解説します。
読み終える頃には、簡単なクラスに対して自分でテストを書けるようになります。
基本の書き方:RSpecの導入から実行まで
手順1:RSpecをインストールする
RSpecはgem(Rubyのライブラリパッケージ)として提供されています。
プロジェクトのディレクトリで、以下のコマンドを実行してインストールします。
bundle init
Gemfileが生成されるので、rspecを追記します。
# Gemfile
source "https://rubygems.org"
gem "rspec"
追記したら、bundle installでインストールします。
bundle install
続けて、RSpecの初期設定ファイルを生成します。
bundle exec rspec --init
このコマンドを実行すると、.rspecファイルとspec/spec_helper.rbが作成されます。
specディレクトリの中に、これからテストコードを書いていきます。
手順2:テスト対象のクラスを用意する
まずは、テストの対象となるシンプルなクラスを用意します。
lib/calculator.rbとして保存します。
# lib/calculator.rb
class Calculator
def add(a, b)
a + b
end
def divide(a, b)
raise ArgumentError, "0で割ることはできません" if b == 0
a / b
end
end
足し算を行うaddメソッドと、0除算を防ぐバリデーション付きのdivideメソッドを用意しました。
手順3:describe・it・expectで最初のテストを書く
テストコードはspec/calculator_spec.rbのように、_spec.rbという名前で保存するのが慣例です。
# spec/calculator_spec.rb
require "calculator"
RSpec.describe Calculator do
describe "#add" do
it "2つの数値を足した結果を返す" do
calculator = Calculator.new
expect(calculator.add(1, 2)).to eq(3)
end
end
describe "#divide" do
it "2つの数値を割った結果を返す" do
calculator = Calculator.new
expect(calculator.divide(6, 2)).to eq(3)
end
it "0で割るとArgumentErrorになる" do
calculator = Calculator.new
expect { calculator.divide(1, 0) }.to raise_error(ArgumentError)
end
end
end
それぞれのキーワードの役割は以下の通りです。
describe:テスト対象をグループ化する。「何についてのテストか」を表すit:具体的なテストケースを1つ書く。「〇〇のとき××になる」という仕様を文章で書くのがポイントexpect:実際の値を渡して、期待する結果と一致するかを検証する
expect(実際の値).to eq(期待する値)という形が、RSpecの最も基本的な書き方です。
エラーが発生することを検証したい場合は、expect { ブロック }.to raise_error(エラークラス)のように、波括弧のブロック形式で書く点に注意してください。
手順4:rspecコマンドでテストを実行する
テストを実行するには、bundle exec rspecコマンドを使います。
bundle exec rspec
すべてのテストが通ると、以下のような結果が表示されます。
Calculator
#add
2つの数値を足した結果を返す
#divide
2つの数値を割った結果を返す
0で割るとArgumentErrorになる
Finished in 0.01234 seconds (files took 0.1 seconds to load)
3 examples, 0 failures
3 examples, 0 failuresという表示から、3つのテストケースがすべて成功したことが分かります。
よくあるつまずきポイント・エラー対処
require忘れによるNameError
❌ Before:requireを書き忘れてクラスが見つからない
わたしが初めてRSpecを使ったとき、spec_helper.rbだけを読み込ませれば、対象のクラスも自動で読み込まれると勘違いしていました。
# spec/calculator_spec.rb(requireなし)
RSpec.describe Calculator do
it "2つの数値を足した結果を返す" do
calculator = Calculator.new
expect(calculator.add(1, 2)).to eq(3)
end
end
これを実行すると、以下のエラーになりました。
NameError:
uninitialized constant Calculator
「クラスは確かに定義したはずなのに、なぜ見つからないんだろう」と原因に気づくまで時間がかかりました。
✅ After:require “calculator”でテスト対象を読み込む
原因は、テスト対象のファイルをrequireしていなかったことでした。
# spec/calculator_spec.rb
require "calculator"
RSpec.describe Calculator do
it "2つの数値を足した結果を返す" do
calculator = Calculator.new
expect(calculator.add(1, 2)).to eq(3)
end
end
さらに、libディレクトリを読み込みパスに追加する必要がある場合は、.rspecファイルに以下を追記しておくと安定します。
# .rspec
--require spec_helper
-I lib
-I libを指定することで、require "calculator"だけでlib/calculator.rbを見つけられるようになります。
NameError: uninitialized constantが出たときは、まず「対象のファイルをrequireしているか」「読み込みパスが通っているか」の2点を疑うとよいでしょう。
まとめ
この記事のポイント
- RSpecは
Gemfileにgem "rspec"を追記し、bundle installでインストールする bundle exec rspec --initで、.rspecとspec_helper.rbが生成されるdescribeはテスト対象のグループ化、itは個別のテストケース、expectは検証を担当するexpect(値).to eq(期待値)が最も基本的な検証の書き方NameError: uninitialized constantが出たら、require忘れと読み込みパスをまず疑う
次に読むべき記事
RSpecの基本を押さえたら、次はRubyの標準テストライブラリであるMinitestとの違いを比較した記事に進むと、テストツール選びの判断軸が身につきます。
タグ: Ruby, 中級者向け, テスト