他の言語と同様にrubyにも様々なテストツールがありますが、その中でも特にrspecというテストツールについて使用方法を記載します。rspecのバージョンは3.1を想定しています。本ページの内容を越えるものは、以下の公式ページをご参照ください。
$ gem install rspec -v 3.1
$ gem list | grep rspec
rspec (3.1.0)
rspec-core (3.1.5)
rspec-expectations (3.1.2)
rspec-mocks (3.1.2)
rspec-support (3.1.1)
GEMパッケージをインストールするとrspecコマンドが使用できるようになります。rspecコマンドを使用して、設定ファイルなどを自動生成しましょう。
$ rspec --init
create .rspec
create spec/spec_helper.rb
rspecコマンドを実行する際に自動で付与される引数を記述できるファイルです。
--color
--format documentation
--require spec_helper
などとしておくとよいです。それぞれの意味については
$ rspec --help
を参照してください。
テスト時に自動で読み込まれるファイルです。各テストにおいて共通の処理があればこのファイルに記述します。
sample.rb
class MyStack
def initialize
@arr = []
end
def push(val)
raise if val.nil?
@arr.push(val)
return val
end
def pop
@arr.pop
end
def size
@arr.size
end
end
spec/sample_spec.rb
require './sample'
RSpec.describe MyStack do
subject { @stack } # ← subject (和訳:テストされる者)
before(:example) do # ← それぞれの 'example' (itブロック) の前で実行される
@stack = MyStack.new # (「before(:each) do」としても同じ意味。エイリアス)
end
describe "#push" do
context "in 正常系" do
it { expect(subject.push(123)).to eq 123 }
it { expect(subject.push('value1')).to eq 'value1' }
it { expect(subject.push(false)).to eq false }
it { expect(subject.push([])).to eq [] }
it { expect(subject.push([])).to be_empty } # としても同じ
end
context "in 異常系" do
it { expect { subject.push(nil) }.to raise_error }
end
end
describe "#pop" do
context "in 正常系" do
context "スタックが空の場合" do
it { expect(subject.pop).to be_nil }
end
context "スタックに値がある場合" do
before do
subject.push 'value1'
subject.push 'value2'
end
it { expect(subject.pop).to eq 'value2' }
it {
subject.pop
expect(subject.pop).to eq('value1')
}
end
end
context "in 異常系" do
it { expect { subject.pop('arg') }.to raise_error ArgumentError }
end
end
describe "#size" do
context "in 正常系" do
it { expect(subject.size).to eq 0 }
it {
subject.push('value')
expect(subject.size).to eq(1)
}
end
context "in 異常系" do
it { expect { subject.size('arg') }.to raise_error ArgumentError }
end
end
end
実行方法
$ rspec ← spec/* のすべてのテストを実行
(or $ rspec spec/sample_spec.rb) ← 特定のspecファイルのみを実行
実行結果例
MyStack
#push
in 正常系
should eq 123
should eq "value1"
should eq false
should eq []
should be empty
in 異常系
should raise Exception
#pop
in 正常系
スタックが空の場合
should be nil
スタックに値がある場合
should eq "value2"
should eq "value1"
in 異常系
should raise ArgumentError
#size
in 正常系
should eq 0
should eq 1
in 異常系
should raise ArgumentError
Finished in 0.006 seconds (files took 0.24701 seconds to load)
13 examples, 0 failures
"Mock" という英単語には "物まね" や "偽物の" といった意味があります。rspecにおけるMockという仕組みを使用すると、あたかもあるクラスのオブジェクトであるかのような「もの」を用意できます。その「もの」に未実装のクラスの物まねを覚えさせることによって、未実装のクラスの存在を前提としたテストコードが記述できます。これによって、ある未実装のクラスに依存した実装済みのクラスのテストを、未実装のクラスの実装を待たずに行うといったことが可能になります。ここで記載する内容を越えるものは公式ページをご参照ください。
rspecのMockという仕組みの中では以下のような用語が登場します。
mymock1_spec.rb
RSpec.describe "Unimplemented Class" do
subject { @unimplemented }
before(:example) do
@unimplemented = double("unimplemented")
end
describe "#unimplemented_method" do
it {
allow(subject).to receive(:unimplemented_method).and_return('value')
expect(subject.unimplemented_method).to eq('value')
}
end
end
実行例
$ rspec spec/mymock1_spec.rb
Unimplemented Class
#unimplemented_method
should eq "value"
Finished in 0.012 seconds (files took 0.24701 seconds to load)
1 example, 0 failures
mymock2_spec.rb
class User
def initialize(name)
@name = name
end
attr_accessor :name
end
RSpec.describe User do
subject { @user }
before(:example) do
@user = User.new('sample name')
end
describe "#unimplemented_method" do
it {
allow(subject).to receive(:unimplemented_method).and_return('value')
expect(subject.unimplemented_method).to eq('value')
}
end
end
実行例
$ rspec spec/mymock2_spec.rb
User
#unimplemented_method
should eq "value"
Finished in 0.012 seconds (files took 0.23501 seconds to load)
1 example, 0 failures
rubyの軽量WebフレームワークであるSinatraにおいて、その本体アプリケーションファイルをrspecでテストする場合に必要となる事項について記載します。
Sinatraのための初期設定として "Rack::Test::Methods" のincludeが追加で必要になります。この処理は複数のテストで必要になることが多いため、共通の処理として "spec/spec_helper.rb" に記述しておきましょう。
spec/spec_helper.rb
RSpec.configure do |config|
config.include Rack::Test::Methods
end
「Hello World」と表示するだけのsinatraの本体アプリケーション "helloworld.rb" があるとします。これをテストするためには、ファイル "spec/helloworld_spec.rb" を作成し内容を以下のようにします。
spec/helloworld_spec.rb
ENV['RACK_ENV'] = 'production'
# Sinatra本体アプリケーションを読み込む
require './helloworld'
describe 'HelloWorld Application' do
# Rack::Testのために必要な設定
def app
Sinatra::Application
end
it "トップページにアクセスすると 'Hello World' と表示される" do
get '/'
expect(last_response).to be_ok
expect(last_response.body).to eq('Hello World')
end
end
get, post, put, delete, head が使用できます。各メソッドには引数が指定できます。例えばgetの場合は以下のようになります。
$ get '/path', params={}, rack_env={}
HTTPメソッドを実行したあとは
が使用できます。例えば
といった値をテストで利用できるようになります。