公開の日記はいまいちしっくりきません。やっぱり公開できるネタしかかけないので、日々の記録としては使いづらいし、誰得な感じ。
ということで日々の記録としての日記は昔ながらの日記帳にするとして、ブログは備忘録とか仕事の宣伝とか、そういうので使おうと思う。
子供が無事退院。
看病疲れでダウンした妻に付き添って一緒に病室で一夜を明かしたが、これは精神的にも肉体的にもきつい。1週間も続けたら、そりゃあ、熱も、出る。
帰宅して子供と遊んだり、片付けをしたりしてると、妻が「ようやく一家って感じがする」。ドタバタだったもんなぁ、本当。
疲れがたまっていたのか、二度寝した。起きたら12時。
妻と子供の顔を見に、病院へ。
と、その道中マックに寄って昼ご飯。
ビバリーヒルズバーガーをクーポンで注文。
なかなかうまい…と思ったが、アボカドソースが口に合わず…これさえなければ文句ないのに。
子供、今日はずっと機嫌が悪かったけど…なかなか元気。
ただ、下痢がひどく、何度もお持つ交換。下痢止めの薬も飲んでくれてないみたい。
20時の面会終了まで一緒にいて、帰宅。
道中、水槽用の緑ボンを交換。閉店処理中のところ、お願いして入れて貰った。ありがとうございました。
帰宅すると、Amazonで予約していた宇宙兄弟17巻が届いていたので、晩ご飯を食べながら読破。18巻まだかなw
我が家も下水道が来るそうで、新しい便器をどれにするか選べとのことなので、いろいろ調べながら選んだ。
どうやら今使ってるシャワートイレが使えるようなので、便器とタンクのみのセットを指定。
くみ取り不要になるのか、ありがたい。
RailsにおけるBDD
外側からのRails開発
- シナリオ
- Cucumber
- 最初のステップ定義
- RSpecでのビュー表現
- RSpecでのコントローラ表現
- RSpecでのオブジェクト表現
- 実装&Cucumber
- 次のステップへ
Cucumber
ステップ定義
- Direct Model Access スタイル
- ActiveRecordモデルを直接操作
- ルーティング、コントローラを素通りするので、この部分のテストにならない
- Simulated Browser スタイル
- Webratを使用
- ルーティング、コントローラも実際の操作と同じ
- JavaScriptに対応できない
- Automated Browser スタイル
- Webrat + Selenium
- ルーティング、コントローラも実際の操作と同じ
- JavaScriptにも対応
- メンテナンスが難しい
- Given
- Direct Model Access スタイル
- データベースを特定の状態にする
- 他の部分でそのモデルのSimulated Browserスタイルでのシナリオがあるとき
- When
- Simulated Browser スタイル
- Webratでシナリオのアクションをシミュレート(ページにアクセスするとか、ボタンを押すとか、フォームに入力するとか)
- フォームフィールドの指定は Label で
- nameなどだと、実装の詳細に依存しやすい(モデルクラス名などがかわると変更が必要になる)
- Then
- Simulated Browser スタイル
- Webratのビューマッチャで期待されるテキストと要素を検証
Selenium
RSpecでのビュー表現
- spec/views/path/to/view.html.erb_spec.rb
- 実際のモデルやコントローラより先にビューを表現する
- モデルやコントローラの実装は関心がない
- 「あったらいい」インスタンス変数のみ
- コントローラで提供すべきインスタンス変数の特定に役立つ
- モデル
- mock_model
- 実際のモデルがないとき
- ActiveRecordの一般的なメソッドがスタブ化されたRSpecモックオブジェクトを生成
- デフォルトで「存在するレコード」のように振る舞う
- 新規レコードのようにしたいときは as_new_record()
- 関心のあるメソッド以外は無視するように as_null_object()
- stub_model
- 実際のモデルが存在するようになったらこちら
- 実際のActiveRecordモデルのインスタンスを生成
- as_null_object()不要
- ただしデータベースにアクセスできない
- ビューで実行すべきでない
- rspec-railsライブラリのカスタムサンプル利用
- Webrat
- have_xpath()
- have_selector()
RSpecでのヘルパー表現
- spec/helpers/application_helper_spec.rb
RSpecでのコントローラ表現
- ビューから切り離して指定
RSpec::Mock
テストダブル
- サンプルにおいて別のオブジェクトの代わりをするオブジェクト
- thingamajig_double = double(‘thing-a-ma-jig’)
- stub() / mock() 同じもの。意図を明確にするために使い分ける。
- RSpec::Mocks::Mockオブジェクト
- メソッドスタブ
- 決められた応答を返すメソッド
- stub()
- 便利な機能
- 1行のショートカット
- 実装の注入(簡易実装・Fakeパターン)
- スタブチェーン stub_chain
- メッセージエクスペクテーション(モックエクスペクテーション)
- 一度も呼び出されないとエラーになるメソッドスタブ
- should_receive()
- 便利な機能(実装との結合が強くなる。特定の要件の表現のみに使用すること)
- カウント(○回だけ呼び出されるべき)
- (at_least | at_most | exactly) times
- once / twice
- 否定のエクスペクテーション
- should_not_receive
- 期待される引数の指定
- with
- 引数マッチャ
- instance_of クラスを指定
- anything 引数は受け取るが何でも良い
- any_args どのような引数でも、あってもなくても
- no_args 引数なし
- hash_including 期待のキーペア
- hash_not_including 含むべきでないキーペア
- 正規表現 文字列の一部でのみマッチング
- カスタム引数マッチャ
- 連続した値を返す
- and_return(nil, nil, …)
- 例外とシンボル
- and_raise
- and_throw
- 順序づけ
- ordered
- 一つのオブジェクトのコンテキストの中だけ
- メソッドスタブのオーバーライド
メッセージエクスペクテーション
- サンプルが実装に密結合だが問題ないのか?
- サンプルが表現している要件の場合は、むしろ当然
- 「ヘッダーに顧客名が使用されること」 … 顧客名オブジェクトの「name」が呼び出されない方がおかしい
- 意味のないメッセージエクスペクテーションは避けるべき
- サンプルの意図を表現するためにだけ使う
- 「太郎」が含まれるのが大事なのではなく、「顧客名」が含まれるのが大事
テスト固有の拡張
- サンプルに特化したオブジェクトの拡張
- オブジェクトを使うオブジェクトが「何を行うか」を明確にする
- 強力だが、乱用注意
- 必要な場面
- 依存関係からの分離
- 作成するのにコストのかかるオブジェクト
- ネットワーク、サーバー、ファイルシステム等の外部システムが関与するオブジェクト
- 他のコストのかかるオブジェクトに依存するオブジェクト
- 動作に時間のかかるオブジェクト
- 不確定性からの分離
- 依存関係を実装せずに進める
- 依存関係の実装のためにオブジェクトから焦点がそれるのを防ぐ
- インターフェイスの発見
- 役割を焦点に合わせる
- オブジェクトが何であるかではなく、何をするか
- 状態ではなくやりとりに焦点を合わせる
- 状態は実装上の詳細
- 内部状態・属性を参照しないようにすることでスペックの堅牢性と柔軟性を維持できる
- 種類
- 部分的なスタブ
- 本物のオブジェクトの、呼び出しが想定される一部のメソッドをスタブにする
- 「WidgetsControllerに正しい属性をPUTすると、widgetのリストにリダイレクトするべき」
- 「有効な属性」は前提であり、それが何かはここで表現したいことではない
- スタブを使わない(そのまま)
- 「有効な属性」の検証ルールを変更されると、サンプルがエラー
- 部分的なスタブを使う
- widget = Widget.new
Widget.stub(:find).and_return(widget)
widget.stub(:update_attributes).and_return(true) - 「有効な属性」が何かはサンプルでは関知しない
- データベース等への依存性も排除できる
- 部分的なモック
- スタブだけでは指定できない、詳細を指定するサンプル
- 本物のオブジェクトに、メッセージエクスペクテーションを設定する
- 「widgetを検索すること」
- widget = Widget.new
Widget.stub(:update_attributes).and_return(true)
widget.should_receive(:find).with(“37”).and_return(widget)
put :update, :id => 37 - 「widgetの属性を更新すること」
- widget = Widget.new
Widget.stub(:find).and_return(widget)
widget.should_receive(:update_attributes).and_return(true)
put :update, :id => 37
リスクとトレードオフ
- 過剰な仕様
- 入れ子のテストダブル
- カバレッジの欠如
- 脆弱なサンプル



最近のコメント