プロぽこ

【直感的に書ける!】RspecでRubyのテストを覚えよう!

どんな言語にもテストを書くための仕組みがあるものです。個人の趣味で書いているプログラムではテストなどは必要ないかもしれませんが、サービスで運用するプログラムではテストは必要不可欠です。

rubyにもrspecというテストの仕組みがあります。書き方さえ覚えればとても直感的に書けるので是非この機会に覚えましょう。



初期設定

ruby が入っている環境であれば「gem」コマンドが入っているのでそれを使って「rspec」をインストールしましょう。

gem install rspec

正常にrspecがインストールができたら下記のコマンドで確認できます。

rspec -v

インストールされていれば下記のコマンドで初期化して、rspecが使える状態にしましょう。下記のコマンドを使用するとspec フォルダが作成されます。

rspec --init

specフォルダが作成されたらそのフォルダ以下に作業フォルダを作成しましょう。今回の場合「sample」フォルダとします。
「spec/sample/」というフォルダ構成となります。このフォルダ以下にテスト対象ファイルとテストファイルを置いていきます。



テストコードを書く

まずは簡単なテストを書いてみましょう。テストを書く前にテスト対象のファイルを作成します。下記の「Hello」クラスはhelloという文字列を返すだけのhelloメソッドを持つクラスです。

# hello.rb

class Hello
  def hello
    return "hello"
  end
end

次に上記の「hello.rb」をテストするプログラムを書きます。テストの意味としては「Helloクラスのhelloメソッドが”hello”という文字列がちゃんと返すかをテストする」ということになります。

テストファイルの命名は「テスト対象ファイル_spec.rb」という名前にする必要があります。

# hello_spec.rb

require "spec_helper"
require_relative "./hello"

describe Hello do
  it "Helloクラスのhelloメソッドが"hello"という文字列がちゃんと返すかをテストする" do
    h  = Hello.new
    expect(h.hello).to eq "hello"
  end
end

「describe」の次にテスト対象のクラス名を指定しましょう。「it」文の後にどのようなテストを行うかを記述しましょう。ここは自由入力ですので本当に正しい内容を記述しておきましょう。

何をテストするか明確でなければわざわざテストを書く意味がなくなってしまいます。今回のテストでは上述したように「Helloクラスのhelloメソッドが”hello”という文字列がちゃんと返すかをテストする」のテストですのでそのようにしっかり記述します。

次に「it」文のブロックの中に実際のテスト内容を記述します。「Hello」クラスのインスタンスを作成し、「hello」という文字列を返すかどうかを「expect」文でテストします。

テストの実行は「ファイル指定」でもできますし「書いてあるテストを全て実行」などもできます。

ファイル指定でテストを実行する場合単純に実行したいテストファイルをrspecの後に指定すればokです。

rspec spec/samplehello_spec.rb

書いてあるテストを全て実行したい場合ただ「rspec」と入力するだけです。ただこれだとテストの状況がよくわからないので「-fd」オプションをつけましょう。

# 全テスト実行
rspec

# 全テスト実行(内容も表示)
rspec -fd

「-fd」オプションを使うとテスト結果は下記のように出力されます。失敗した場合 failure がカウントされます。

Hello
  Helloクラスのhelloメソッドがhelloという文字列がちゃんと返すかをテストする

Finished in 0.00117 seconds (files took 0.08732 seconds to load)
1 example, 0 failures

ちなみにですが「-fj」とすれば結果がjsonとして出力され、「-fh」とすれば結果がhtmlとして出力されます。テストレポートなどをまとめて置く場合に有用でしょう。

エラーのテストを書く

テストを書く場合の基本として「正常系」のテストと「異常系」のテストを書くことになります。「正常系」のテストとは上述したような想定した動作をちゃんとするかのテストです。

逆に「異常系」のテストとは想定しない値がきた場合にちゃんと想定したエラーがでるかどうかをテストするものです。

先ほどの「Hello」クラスにエラーを投げるメソッドを追加してみます。このメソッドは呼ばれると「StandardError」というエラーを投げるメソッドです。

要は呼ばれたかならずエラーとなるメソッドとなっています。

class Hello
  def hello
    return "hello"
  end

  def throw_error
    raise StandardError
  end
end

次にテストプログラムに下記のようなテストを追加し、上記で追加したメソッドを呼び出してみましょう。想定したエラーがちゃんと出るかをテストします。

先ほどと同様に「it」文の後にはテストの説明を書きます。その後「Hello」クラスを作成して、raise_errorという構文を用いてエラーが出るかどうかをチェックしています。

require "spec_helper"
require_relative "./hello"

describe Hello do
  it "Helloクラスのhelloメソッドがhelloという文字列がちゃんと返すかをテストする" do
    h  = Hello.new
    expect(h.hello).to eq "hello"
  end

  it "Helloクラスのthrow_errorメソッドがStandardErrorを投げることをテストする" do
    h  = Hello.new
    expect{h.throw_error}.to raise_error(StandardError)
  end
end

このメソッドを呼ぶとエラーが出ますが、テスト的にはこれがちゃんとエラーが出るかのテストですので、正常に通ります。
ポイントとしては「expect」メソッドを「{}」で囲む点と、「raise_error」で評価する点です。

rspec -fd

Hello
  Helloクラスのhelloメソッドがhelloという文字列がちゃんと返すかをテストする
  Helloクラスのthrow_errorメソッドがStandardErrorを投げることをテストする

Finished in 0.00197 seconds (files took 0.07765 seconds to load)
2 examples, 0 failures

まとめ

この記事ではrubyのプログラムをrspecというモジュール使ってのテストの書き方を解説しました。「正常系」「異常系」ともにとても直感的に書けるものとなっていることがおわかりいただけたと思います。

テストがないプログラムはバグの温床となりますので可能な限りテストをかいてプログラムの品質を上げましょう。