🐘
RSpec の実行順序と AAA パターンについて
概要
単体テストの考え方/使い方という本で、
AAA パターンというものを学びました。
今回は RSpec の実行順序を、この AAA パターンに絡めて解説していきます。
AAA バターンとは
単体テストの構造ののことで、以下の3つで構成されている。
- Arrange(準備)
- Act(実行)
- Assert(確認)
RSpec の例題
RSpec では、describe
, context
, let
, let!
, before
が準備に相当し、
it
が実行、 expect
(RSpec it 句が通ればグリーンになる) が 確認に当たります。
これらは準備→実行→確認の順になっています。
準備フェーズ
- すべての
describe
句とその中のcontext
句が実行 - それぞれの
it
句の前に定義されるlet!
、before
が実行
実行フェーズ
it
句内が実行
確認フェーズ
it
句内の expect
句が実行
以下のような RSpec で見てみましょう。
sample_spec.rb
require 'rails_helper'
RSpec.describe "Sample Spec" do
let(:num0) do
pp "let num0"
end
let!(:num0_2) do
pp "let! num0_2"
end
describe "describe1" do
pp "describe1"
let(:num1) do
pp "let num1"
end
before "before1" do
pp "before1"
end
context "context1" do
pp "context1"
let!(:num2) do
pp "let! num2"
end
before "before2" do
pp "before2"
end
it "it1" do
pp "it1"
end
end
context "context2" do
pp "context2"
let!(:num3) do
pp "let! num3"
end
before "before3" do
pp "before3"
end
it "it2" do
pp "it2"
end
end
end
describe "describe2" do
pp "describe2"
context "context3" do
pp "context3"
before "before4" do
pp "before4"
end
let!(:num4) do
pp "let! num4"
end
it "it3" do
pp "it3"
end
end
end
end
これを実行すると、以下のような出力がされます。
各々の実行タイミングはコメントの通りです。
> bundle exec rspec spec/models/sample_spec.rb
"describe1" # describe1 が実行.......................(準備フェーズ)
"context1" # describe1 内の context1 が実行..........(準備フェーズ)
"context2" # describe1 内の context2 が実行..........(準備フェーズ)
"describe2" # describe2 が実行.......................(準備フェーズ)
"context3" # describe2 内の context3 が実行..........(準備フェーズ)
"let! num0_2" # context1 内の it1 前の let! が実行.......(準備フェーズ)
"before1" # context1 内の it1 前の before1 が実行....(準備フェーズ)
"let! num2" # context1 内の it1 前の let! が実行.......(準備フェーズ)
"before2" # context1 内の it1 前の before2 が実行....(準備フェーズ)
"it1" # context1 内の it1 が実行................(実行フェーズ)
. # it1 内が成功........................... (確認フェーズ)
"let! num0_2" # context2 内の it2 前の let! が実行...... (準備フェーズ)
"before1" # context2 内の it2 前の before1 が実行... (準備フェーズ)
"let! num3" # context2 内の it2 前の let! が実行...... (準備フェーズ)
"before3" # context2 内の it2 前の before3 が実行....(準備フェーズ)
"it2" # context2 内の it2 が実行................(実行フェーズ)
. # it2 内が成功........................... (確認フェーズ)
"let! num0_2" # context3 it3 前の let! が実行...........(準備フェーズ)
"before4" # context3 it3 の前の before4 が実行.......(準備フェーズ)
"let! num4" # context3 it3 の前の let! が実行..........(準備フェーズ)
"it3" # context3 内の it3 が実行................ (実行フェーズ)
. # it3 内が成功............................(確認フェーズ)
まとめ
結果を見てみると、RSpec では、まずすべての describe
句と context
句が実行され、
テストの構造を定義しているようです。(準備)
次に 各 it
句を実行する前に、before
, let!
が実行され、確認で使用する値を定義しています。(準備)
上記の準備が終わると、it
句が実行されています。(実行)
最後に各 it
句内が期待通りになっているか検証されています(確認)
また、let
に関しては遅延評価で、コード上ではどこからも呼ばれていないため、出力されていません。
Discussion