{{tag>book}} ====== Effective Testing with RSpec 3 ====== ===== 1 ===== * Tests .. あるコードが適切に動くかどうか * Specs .. 望む動作を記述する * Examples .. 例を示す インスタンス変数の欠点 * ミススペルしていると特にエラーを出さずただnilを出す * 変更が全体に及びリファクタリングしにくくなる * いちいちフックでやっていたら時間がかかる * 操作の結果を保存する、メモ化を利用する。典型的なのは def sandwich @sandwich ||= Sandwich.new('delicious', []) end * ゲームを作るときによく見たやつ。これがメモ化なんですね。 ===== 2 ===== * exampleを論理的に構造化する * 適切な詳細さで望む結果を書く * セットアップを共有する * contextはオブジェクトを変化させるテストのときに用いる * 出力を見やすい形式に変えられる ''rspec --format documentation'' * シンタックスハイライトもできる ''gem install coderay'' ''rspec fd'' * キーワードを含むテストだけを実行: ''-e keyword'' * RSpec-modeがある * あらかじめテストしたい見出しを書いておけばワークフローになって忘れない。pendingを使う。 ===== 3 ===== * メモを忘れる。 ===== 4 ===== * いきなりsinatraをやらされる。 * requestのテストでは、レスポンスの返すステータスコードで動作を確認したりする。内部については考えないということ。ブラックボックステスト。 ===== 5 ===== * Umm... * before, letはDRYを実行するリファクタリングに便利。 * 急に出てきたコイツ↓ allow(ledger).to receive(:record) .with(expense) .and_return(RecordResult.new(false, 417, 'Expense incomplete')) は何なんだよ!ledgerのrecordメソッド。RecordResultがrecordに反応するかどうか? * とりあえずLedgerは元帳。記録する役割。gemの名前とかではない。Structで一時的に作った中身のない引数だけとるヤツだった。。 * なんとなくわかり始める。テストというよりHTTPメソッドのやりとりがよくわかってなかったんだな。 ===== 6 ===== * integration spec * GETメソッドを追加する。 * bundle exec rackup config.ru #sinatra起動 * 最初にテストを作っておけばいちいちブラウザでできたか確認する必要がない。 * ''bundle exec rspec --bisect --seed 32043'' * 毎回DBをrollbackするために、設定を追加する。requireをヘルパーに追加して、:dbが使われるときに読み込むようにする。 ===== 7 ===== 重複をなくす方法いろいろ。フックとかincludeとか。すごい綺麗になった。 ===== 8 ===== メタデータをつけた効率的なテスト実行。 ===== 9 ===== カスタマイズ。 出力を必要なものに絞るとか。あまりいらないような。 ===== 10 ===== expectation matcherは正規表現のようなものだ。文字列のかわりに特定のオブジェクトでマッチする。 175ページは興味深い。マッチャがどう反応するか試している。適当に作ったオブジェクトをexpectにわたすと、no method errorが出る。matches? がないらしい。matches?を追加する。 matcher = Object.new def matcher.matches?(actual) actual == 1 end 1だと正を返すような。それで、 expect(1).to matcher # => true expect(2).to matcher # => no method error, 'failure_message' def matcher.failure_message 'failure' end irbでマッチャをチェック require 'rspec/expectations' include RSpec::Matchers マッチャを組み合わせるときに''.and''もしくは''&''などを使う。or,not.. ''description''がメソッドを文字に変更するようす [57] pry(main)> (start_with(1) & end_with(9)).description => "start with 1 and end with 9" ↑を利用してit内を省略できるときがある。一行のマッチャのとき? # fish_oilが重複している it 'should not include:fish_oil' do expect(CookieRecipe.new.ingredients).not_to include(:fish_oil) end => should not include:fish_oil specify do expect(CookieRecipe.new.ingredients).not_to include(:fish_oil) end => should not include:fish_oil 最初にsubjectを指定しておくことでexpectにいつも書く手間が省けることがある。is_expected_to ===== 11 ===== さらなるmatcher。 特定の型に反応する''primitive matcher'' 「同じ」にもいろいろある。 * 同じオブジェクト * 同じ値 * 同じハッシュ(?) なんの脈絡もなくハリーポッターが出てきて笑う U2も。作者がイギリスの人なんだなきっと。 ===== 12 ===== 新しいマッチャを定義する ===== 13 ===== スタブ、モック、スパイ、ヌルオブジェクト。 システムの一部を独立させてテストしやすいようにする テスト用のはりぼてのクラスやメソッドを作ったり、テストのときだけ定義される定数なんかもできる。stub_const 前者3つの違いがよくわからん…。スタブ: 受信メッセージ用。依存するオブジェクトを決まりきった反応しかしないオブジェクトに変える。 モック: 送信メッセージ用。 ===== 14 ===== 設定 ===== 15 ===== ダブルを効率的に