「RSpecの構文」の編集履歴(バックアップ)一覧はこちら

RSpecの構文」(2010/01/26 (火) 23:56:06) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

* 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).items|配列などのコレクションオブジェクトが、n個以上の要素を持っているか。(should_notは使用できない) :have_at_most(n).items|配列などのコレクションオブジェクトが、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 ** スタブ/モック機能 RSpecには、簡単なスタブとモックを組み込む機構が用意されている。 ここでは、RSpecのスタブ/モック機能に焦点を当てる。 簡単な機構なので、もっとダイナミックな仕組みが欲しい場合は、mochaやflex_mockなどのモック専用ライブラリ/フレームワークを利用した方が効率がいい。 *** スタブとモックの違い スタブもモックも、UnitTestで必要になる、内部使用している部品をエミュレートすることで、本物の部品の代用となる空箱のようなもののことを指す。 なぜこんなものが必要なのか?それは、こんな理由によっている。 -全てを「本物」でテストしようとすると、「全てが揃わないとテストできない」という本末転倒な事が起こりかねない。 -たとえば時刻に関するオブジェクトのように、システムの構成によって変化してしまうオブジェクトがあると、テスト環境によって差異ができてしまう。 -UnitTestが大きな問題に移ると段々と結合テスト化してしまう、という問題がある。 ある程度のスタブ/モックを使用することで、これらの問題が有機的にクリアされていく。 ※ ただし、スタブ/モックを多用し過ぎると、今度はインタフェース不一致の発見を先送りにする、という状況にもなりかねない。このあたりはさじ加減が必要。 では、スタブとモックの違いはなにか? 最近、Martin Fowlerらが、このスタブとモックの違いに関して面白い考察をしていた。この定義は今や一般化しており、RSpecでもこの意味でスタブとモックとを使い分けている。 :スタブ|「インタフェースの定義だけ一致していれば、中身はどのように動いてもいいので、とりあえず用意しておく空箱」のことを言う。 :モック|「インタフェースの定義だけではなく、それがどの様に呼ばれるか、またそれに対して何を返すべきかまでを模倣した空箱」のことを言う。 *** スタブ 何かのクラスのアクセッサをスタブ化するときは、次の構文でアクセッサをスタブに摩り替える。 [クラス].stub!(:[アクセッサ]).and_return([戻り値]) # [クラス]は[アクセッサ]をスタブ化し、[戻り値]を返す。 たとえば次のように書くと、Stringクラスのsizeメソッドが、必ず10を返却するようになる。 String.stub!(:size).and_return(10) *** モック 何かのクラスのアクセッサをモック化するときは、次の構文でアクセッサをモックに摩り替える。 [クラス].should_recieve(:[アクセッサ]) # [クラス]は[アクセッサ]が呼ばれることを期待する。 [クラス].should_recieve(:[アクセッサ]).and_return([戻り値]) # [クラス]は[アクセッサ]が呼ばれることを期待し、その結果として[戻り値]を返す。 [クラス].should_recieve(:[アクセッサ]).with([引数]).and_return([戻り値]) # [クラス]は[アクセッサ]が[引数]で呼ばれることを期待し、その結果として[戻り値]を返す。 たとえば次のように書くと、Arrayクラスのsliceメソッドが引数(5,5)で呼ばれることを期待し、その結果として[5,6,7,8,9]を返却するようになる。 Array.should_recieve(:slice).with(5,5).and_return([5,6,7,8,9]) ----
* 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の中に記述する。 基本的な書き方は、次のとおり。 it "テストの説明" do [テスト対象オブジェクト].[テスト対象メソッド].should == [結果] end *** 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).items|配列などのコレクションオブジェクトが、n個以上の要素を持っているか。(should_notは使用できない) :have_at_most(n).items|配列などのコレクションオブジェクトが、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 ** スタブ/モック機能 RSpecには、簡単なスタブとモックを組み込む機構が用意されている。 ここでは、RSpecのスタブ/モック機能に焦点を当てる。 簡単な機構なので、もっとダイナミックな仕組みが欲しい場合は、mochaやflex_mockなどのモック専用ライブラリ/フレームワークを利用した方が効率がいい。 *** スタブとモックの違い スタブもモックも、UnitTestで必要になる、内部使用している部品をエミュレートすることで、本物の部品の代用となる空箱のようなもののことを指す。 なぜこんなものが必要なのか?それは、こんな理由によっている。 -全てを「本物」でテストしようとすると、「全てが揃わないとテストできない」という本末転倒な事が起こりかねない。 -たとえば時刻に関するオブジェクトのように、システムの構成によって変化してしまうオブジェクトがあると、テスト環境によって差異ができてしまう。 -UnitTestが大きな問題に移ると段々と結合テスト化してしまう、という問題がある。 ある程度のスタブ/モックを使用することで、これらの問題が有機的にクリアされていく。 ※ ただし、スタブ/モックを多用し過ぎると、今度はインタフェース不一致の発見を先送りにする、という状況にもなりかねない。このあたりはさじ加減が必要。 では、スタブとモックの違いはなにか? 最近、Martin Fowlerらが、このスタブとモックの違いに関して面白い考察をしていた。この定義は今や一般化しており、RSpecでもこの意味でスタブとモックとを使い分けている。 :スタブ|「インタフェースの定義だけ一致していれば、中身はどのように動いてもいいので、とりあえず用意しておく空箱」のことを言う。 :モック|「インタフェースの定義だけではなく、それがどの様に呼ばれるか、またそれに対して何を返すべきかまでを模倣した空箱」のことを言う。 *** スタブ 何かのクラスのアクセッサをスタブ化するときは、次の構文でアクセッサをスタブに摩り替える。 [クラス].stub!(:[アクセッサ]).and_return([戻り値]) # [クラス]は[アクセッサ]をスタブ化し、[戻り値]を返す。 たとえば次のように書くと、Stringクラスのsizeメソッドが、必ず10を返却するようになる。 String.stub!(:size).and_return(10) *** モック 何かのクラスのアクセッサをモック化するときは、次の構文でアクセッサをモックに摩り替える。 [クラス].should_recieve(:[アクセッサ]) # [クラス]は[アクセッサ]が呼ばれることを期待する。 [クラス].should_recieve(:[アクセッサ]).and_return([戻り値]) # [クラス]は[アクセッサ]が呼ばれることを期待し、その結果として[戻り値]を返す。 [クラス].should_recieve(:[アクセッサ]).with([引数]).and_return([戻り値]) # [クラス]は[アクセッサ]が[引数]で呼ばれることを期待し、その結果として[戻り値]を返す。 たとえば次のように書くと、Arrayクラスのsliceメソッドが引数(5,5)で呼ばれることを期待し、その結果として[5,6,7,8,9]を返却するようになる。 Array.should_recieve(:slice).with(5,5).and_return([5,6,7,8,9]) ----

表示オプション

横に並べて表示:
変化行の前後のみ表示: