RSpecの構文
慣習
RSpec用のテストとして書くテストコードは、[テスト対象のファイル]_spec.rb という名前でつくる。
なにはなくともrequire
require 'lru_cache'
テスト対象のファイルを読み込ませる。
ちなみに、RSpecの何かをrequireする必要なない。
まずは基本
describe do
end
で、一番外側のブロックを記述する。
通常は、次のようにテスト対象のクラスを宣言しておく。
describe LRUCache do
end
また、一緒に説明を付けることも可能。
describe LRUCache, "を初期化する場合" do
end
もちろん、説明だけにすることも可能。
describe "LRUCacheのケース" do
end
describeの中
describeの中にもdescribeを重ねられる
たとえば、同じクラスのテストでも、初期化のテストをがっつりやって、次にhogeメソッドのテスト、そしてfugaメソッドのテストを…とやっていくと、必然的にテストが長く見づらくなってくる。
たとえば、hogeメソッドのテストとfugaメソッドのテストとでは、前準備で必要なものがぜんぜん違う。
そんなときには、describeのなかにさらにdescribeを書いて、整理をつける。
describeの説明文
ここに何を書くべきか。
自然に仕様書っぽく構成した文書にしたい場合、次のように気をつけて記述してみるといい。
[クラス名], [て/に/を/は/の]○○する場合(ケース)
※クラス名は、ひとつ上のdescribeでまとめてしまった方が記述がスッキリするのは、言うまでも無い。
テストの前準備 before
テスト(it)を実行する前に必要な、テストと直接は関係ない準備のための処理を記述する。
たとえば、テスト対象のオブジェクトを生成して、インスタンス変数に入れたり。
たとえば、モックやスタブを用意して、本物のオブジェクトと摩り替えたり。
たとえば、ファイルを用意したり。
before :each do
end
before :all do
end
eachを指定したbeforeは、各テスト(it)のたびに、その前に必ず実行される。
allを指定したbeforeは、describeの最初に一度だけ実行される。
テストの後処理 after
テスト(it)を実行した後に必要な、テストと直接は関係ない後片付けのための処理を記述する。
after :each do
end
after :all do
end
eachを指定したafterは、各テスト(it)を実行するたびに、その後に必ず実行される。
allを指定したafterは、describeの最後に一度だけ実行される。
itの中
テストのコードは、すべてitの中に記述する。
基本的な書き方は、次のとおり。
[テスト対象オブジェクト].[テスト対象メソッド].should == [結果]
itの説明文
ここに何を書くべきか。
自然に仕様書っぽく構成した文書にしたい場合、次のように気をつけて記述してみるといい。
[どのような操作をする]と、[その結果はどうなる]。
基本的な機能要件を説明する場合
は、○○すると、××になる。
特殊な機能要件や、エラー的な機能要件を説明する場合
もし、○○すると、××になる。
shouldメソッド
shouldメソッドは、そのオブジェクトの状態を確認し、指定された状態であるか否か(~であるべき)を検査する。
== 演算子のほか、be系のMatcherが多数用意されている。
全てのオブジェクトに動的に加えられたメソッドなので、基本的には何でも検査可能。
should_notメソッド
shouldと違い、こちらは否定検査(~であってはいけない)をするときに使用する。
Matcher群
shouldで検査できるよう、多数のMatcherが用意されている。
- == expected
- ==比較の結果が同じか
- be_true
- 真であるか
- be_false
- 偽であるか
- be_nil
- nilか
- be_empty
- Arrayが空か
- be_an_instance_of Class
- クラスがClassと一致するか
- be_a_kind_of Class
- クラスが指定Class、もしくはそのサブクラスか
- have_key key
- keyがあるか
- be_close E,D
- 数値が、E~Dの範囲に収まっているか
- change receiver,message,&block
- Procオブジェクトが変化するか
- change(receiver,message,&block).by value
- Procオブジェクトが指定された値で変化するか(should_notは使用できない)
- change(receiver,message,&block).from(before).to(after)
- Procオブジェクトがbeforeからafterに変化するか(should_notは使用できない)
- eql expected
- ==とほぼ同義((eql?で比較)
- equal expected
- 同じオブジェクトか
- have(n).items
- 配列などのコレクションオブジェクトが、n個の要素を持っているか。
- have_exactly(n).items
- 配列などのコレクションオブジェクトが、ちょうどn個の要素を持っているか。(should_notは使用できない)
- have_at_least(n).name
- 配列などのコレクションオブジェクトが、n個以上の要素を持っているか。(should_notは使用できない)
- have_at_most(n).name
- 配列などのコレクションオブジェクトが、n個以下の要素を持っているか。(should_notは使用できない)
- include expected
- 配列などのコレクションオブジェクトに、expectedが入っているか。
- match regexp
- 正規表現regexpにマッチするか。
- raise_error
- 例外が発生するか。
- raise_error Expected
- Expectedな例外が発生するか。
- raise_error Expected,message
- Expectedな例外が、messageを伴って発生するか。
- raise_error Expected,regexp
- Expectedな例外が、正規表現にマッチするメッセージを伴って発生するか。
- respond_to method,method,method...
- オブジェクトが、指定メソッドを全て持つか。
- satisfy {|e| ...}
- ブロックの実行結果(eにテストオブジェクトが渡される)が真になるか。
- thorw_symbol(symbol=nil)
- symbolがthrowされるか。
書いてる本人が、使ったことがないMatcherが多数。
例外が発行されたかどうかはどうチェックする?
次のようにすると、例外の捕捉ができ、例外発行チェックができる。
proc{ [ターゲットオブジェクト].[ターゲットメソッド] }.should raise_error(ArgumentError)
モック機能