RSpec
コマンド
rspec spec/hoge.spec -f d --dry-run
あるspecのテスト項目一覧を見る
rspec --only-failures
失敗したテストのみ
rspec --fail-fast
失敗したらそこでテスト停止
rspec --order random
ランダムな順番で実行
rspec --profile 10
最も遅いテスト10個
rspec --out results.txt
rspec --out tmp/$(date +%s).txt
テストの出力結果を保存
豆知識
.rspecファイルはrspec実行時に自動的に読み込まれるので、デフォルトのrspec起動オプションとか書いておくと良い
/icons/hr.icon
let
遅延評価される
let + createを使うと遅延評価故に評価されるタイミングでDBに値が作成されるためActiveRecordクエリタイミングで値がないなどでテストが失敗するパターンがあるので注意
let!を使うと正格評価してくれる
create
let(:product) { create(:product) }
@product = FactoryBot.create(:product)
上と下は同じ
before
グループでの前処理
subject
テスト対象のオブジェクト(またはメソッドの実行結果)が明確に一つに決まっている場合はdryに書ける
is_expectedで対象オブジェクトが評価される
is_expected
allow
expect
allow
allow_any_instance_of
instance_double
pending
it/example/specify
全く同じメソッド
個人的には全部itでいいと思ってる
it_behaves_like
shared_examplesと組み合わせる
新しいcontextを生成し、そこにテストコードを埋め込む
shared_examplesを使い回す
shared_examplesに共通のマッチャテストを書いてdryにすることができる xit/xdescribe/xcontext
xを付けるとそのグループはスキップ
/icons/hr.icon
モック
本物のふりをするニセモノのプログラム
double/spy
double('Twitter client').as_null_object
as_null_objectでどんなメソッドが呼ばれても許容するようにする
存在しないメソッドをコールしても良いし、実際の異なる引数形式でメソッドを呼び出しても良い「何でもあり」な状態
and_call_originalを使うことで本物のオブジェクトの処理を呼び出すことができる
code:ruby
user = instance_double("User", email: "mock@example.com")
allow(user).to receive(:username).and_call_original
instance_double/instance_spy
Verifying doubleオブジェクトを返す共通点がある
テストダブル対象のインスタンスに存在しないメソッドがスタブされた場合や、引数が異なる形式でメソッドが呼び出された場合にエラーを起こしてくれるという機能を持つオブジェクト
instance_double
メソッドを明示的にallowで定義する必要がある
/icons/point.icon呼び出すメソッドの返り値や呼び出し時の引数に関心がある場合に使用する
instance_spy
as_null_obujectで全部のメソッドについて自動で応答する
/icons/point.iconメソッドが呼び出されたかどうかのみに関心があり、返り値や呼び出し時の引数に関心が無い場合に使用する
allow
code:ruby
allow(user).to receive(:convert_name) do
user.name = user.name.downcase
end
allow(実装を置き換えたいオブジェクト).to receive(置き換えたいメソッド名).and_return(返却したい値やオブジェクト)
allow_any_instance_of
allow_any_instance_of(クラス名).to receive(メソッド名).and_return(戻り値)
allowとの違い
allowはオブジェクト一つの実装を置き換える
allow_any_instance_ofはクラスの全インスタンスの実装を置き換える
/icons/point.icon非推奨
receive_message_chain
allow / allow_any_instance_ofのモックするメソッドをメソッドチェーンで指定できる
allow(page).to receive_message_chain(:items, :find_by).and_return item
特定の引数で呼ばれた時に返す結果を変える
code:ruby
# 引数が 2, 3 のときのみ 5 を返すようにモック
allow(calculator).to receive(:add).with(2, 3).and_return(5)
# 引数が 7, 8 のときのみ 15 を返すようにモック
allow(calculator).to receive(:add).with(7, 8).and_return(15)
stub_const
stub_const("MyClass::MY_CONSTANT", "fake_value")
spy よりも double、double よりも instance_double のほうがより厳密なので、基本的には instance_double を使うのが良い
instance_double ほど厳密にメソッドの定義を検証しなくて良い場合は double を使い、呼び出しているすべてのメソッドをまとめてスタブしたい場合 (返り値がなんでも良い場合に限る) は spy を使う、という使い分け
マッチャ
期待値と実際の値を比較して、一致した(もしくは一致しなかった)という結果を返すオブジェクト
expect(...).to xxx の to の直後に出てくるやつ(xxx の部分)がマッチャ
to / not_to / to_not
コレ自体はマッチャではない
マッチャの実行結果を受け取って、テストをパスさせるか否かを判断するRSpecのメソッド
eq
expect(1 + 2).to eq 3
同値であればパス
be
expect(1 + 2).to be >= 3
等号・不等号と組み合わせて、値の大小を検証するとき
同一インスタンスであればパス
eqと違い同値でも異なるインスタンスであればエラー
be_truthy / be_falsey / be_empty
change + from / to / by
code:ruby
expect(x.size).to eq 3
x.pop
expect(x.size).to eq 2
expect{ x.pop }.to change{ x.size }.from(3).to(2)
expect{ x.pop }.to change{ x.size }.by(-1)
# ユーザーが削除されるとブログも削除されているテスト
expect{ user.destroy }.to change{ Blog.count }.by(-1)
メソッド前後の状態変化をテストできる
expectにブロックを渡すのがポイント
raise_error
assert_queries
クエリの発行回数をテストできる
code:ruby
assert_queries(1) { User.first }
/icons/hr.icon
参照