* RSpecの構文 見本は、これ http://github.com/mitim/tddbc-lrucache/blob/master/lru_cache_spec.rb ** 慣習 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) ** モック機能