初めてのRSpec
今回は基本的なRSpecの使い方を見ていこうと思います。
まず、RSpecが何なのかを見てみましょう。
この記事がわかりやすいです。
一言で言うと、テストを標準よりいい感じにかけるDSLです。
この記事は使い方を見ていくので、標準のTest::Unitよりどういい感じなのかはここでは割愛します。
興味が湧いたらぜひ標準のTest::Unitと比較してみてください。
さっそくRSpecのコードを書いてみましょう。
変数helloの中身が"Hello, World!であることをテストするコードを書いてみます。
テスト駆動開発(TDD)を意識して、テストを先に書きます。
コードを書く前に、RSpecが動くようにしましょう。
$ rspec --init
これで、カレントディレクトリにspecというディレクトリが出来ます。
そして、specディレクトリの中にはspec_helper.rbがあります。
とりあえず、このspec_helperは無視して簡単なテストを書きましょう。
specディレクトリの中にRSpecのコードを置きます。ファイル名は*_spec.rbのように、拡張子の前に_specをつけましょう。
それでは、スペックファイルを編集します。ファイル名はhello_spec.rbでいきます。
$ vim spec/hello_spec.rb
今回のテスト内容は、変数helloの内容が"Hello, World!"であるかテストすることです。
とりあえず、無邪気にRubyのコードで書いてみます。
describe "超簡単なRSpecコード" do hello == "Hello, World!" end
テストが書けました!実行してみます。
$ rspec spec
こんなんが出てきました。
undefined local variable or method `hello' for main:Object (NameError)
helloなんて変数を書いてないんだからNameErrorが出るのは当然ですね。
では、このテストに通るようにコードを書きましょう。
$ vim spec/hello_spec.rb
変数helloに"Hello, World!"を入れます。
下のコードをhello_spec.rb先頭に追加してください。
hello = "Hello, World!"
これでテストに通るはずです。また実行してみましょう。
$ rspec spec
無事通りました!
ですが、このコードはRSpecのメソッドを使っていないため、残念な感じです。
テストの部分をRSpecのメソッドを使ったものに書き換えます。
describe "超簡単なRSpecコード" do it "変数helloの内容はHello, World!" do expect(@hello).to eq "Hello, World!" end end
itメソッドは引数にブロックを取ります。
テストのコードをブロック内に記述します。
なんかそれっぽくなりました。RSpecはすごく英語っぽくて読みやすいですよね。
次に、変数helloに値を入れるところもいけてません。
別ファイルにするか、beforeブロックに入れたいです。
今回は一行しかないので、beforeブロックに入れましょう。
以下のコードをdescribeブロックの先頭に入れます。
before { @hello = "Hello, World!" }
beforeブロックの中身はテスト実行前に実行されます。
helloの前の@はhelloがローカル変数のままだと、helloがbeforeブロック内でしか生きられないからつけました。
書き換えた後のhello_spec.rbはこんな感じ。
describe "超簡単なRSpecコード" do # テストをする前に変数helloに値をセットする before { @hello = "Hello, World!" } # テストコード it "変数helloの内容はHello, World!" do expect(@hello).to eq "Hello, World!" end end
かなりそれっぽくなりました。
このコードを実行すれば、テストには通ります。
こんな感じに。
ただ、この実行結果って情報量が少なくありませんか?
せっかくdescribeとitの後に文字列を書いたのに、表示されないなんてもったいないです。
というわけで、書いた文字列が表示されるようにしましょう。
.rspecを書き換えます。
$ vim .rspec
--formatの後ろのprogressをdocに書き換えます。
これで実行してみましょう。
コード内に入力した文字列が表示されました!
これで見やすくなりました。
ちょっとやりたいことがあるので、変数fooの中が'bar'か判定するコードを追加します。
hello_rspec.rbを書き換えます。
describe '超簡単なRSpecのコード' do context 'helloのテスト' do before { @hello = "Hello, World!"} it '変数helloの内容はHello, World!' do expect(@hello).to eq 'Hello, World!' end end context 'fooのテスト' do it '変数fooの内容はbar' do expect(@foo).to eq "bar" end end end
複数のテストを書くときに、contextでブロックを分けるのをやりたかったのでした。
さっそく、テストに落ちるために実行してみましょう。
無事、テストに落ちましたか?
今回は、RSpecのメソッドで書いたので、NameErrorではなくまっとうにfailureが出たはずです。
こんな感じ。
テストに通って、今回は終わりにしましょう。
以下のコードをfooのコンテキストの先頭に書きます。
before { @foo = "bar" }
書けたら実行してみましょう。
無事に通りました。