RSpecを始めたばかりの人にとって、letやcontextは最初は少し難しく思えるかもしれません。
しかし、letやcontextを使いこなすことでテストの見通しを格段に良くすることができます。
このエントリでは、RSpecのletとcontextの使ってテストの見通しを良くする方法を解説します。
今回テストするのは次のように与えられた引数を加算するadd
メソッドです。
1点注意しなければならないのは、引数a
, b
のどちらかが整数値でなければnil
を返す点です。
class Calculator
def add(a, b)
return unless a.is_a?(Integer) && b.is_a?(Integer)
a + b
end
end
実行結果も見ておきましょう。実行結果は次のようになります。
calc = Calculator.new
puts "a: 1, b: 2 => #{calc.add(1, 2)}" # a: 1, b: 2 => 3
puts "a: nil, b: 2 => #{calc.add(nil, 2)}" # a: nil, b: 2 =>
puts "a: 1, b: nil => #{calc.add(1, nil)}" # a: 1, b: nil =>
add
メソッドのテストを、最初はletやcontextを使わないで書いてみます。おそらく次のようになるでしょう。
RSpec.describe "Calculator" do
describe "#add" do
it "returns the sum" do
a = 1
b = 2
calc = Calculator.new
expect(calc.add(a, b)).to eq(a + b)
end
end
end
しかし、これではa
やb
が整数値でない場合のテストが足りません。そこでcontext
の出番です。
まず、context
によってテストのコンテキストを明示してみます。
a
とb
が整数値であるときを表すためにcontext "when both a and b are integer"
を追加します。
RSpec.describe "Calculator" do
describe "#add" do
context "when both a and b are integer" do
it "returns the sum" do
a = 1
b = 2
calc = Calculator.new
expect(calc.add(a, b)).to eq(a + b)
end
end
end
end
これによって「a
とb
の両方が整数値のとき」が明確になりました。
同じようにして「a
が整数値でないとき」と「b
が整数値でないとき」のコンテキストを追加します。
RSpec.describe "Calculator" do
describe "#add" do
context "when both a and b are integer" do
...
end
context "when a is not an integer" do
it "returns nil" do
a = nil
b = 2
calc = Calculator.new
expect(calc.add(a, b)).to ne_nil
end
end
context "when b is not an integer" do
it "returns nil" do
a = 1
b = nil
calc = Calculator.new
expect(calc.add(a, b)).to be_nil
end
end
end
end
context
とit
を読むだけで、どんなときに何が返ってくるかがわかりやすいテストになりました。
しかし、context
ごとに変わる引数がどうなっているかは、it
の中身を見なければわかりません。
そこでlet
を使ってさらに見通しを良くします。
context
を使って「a
とb
が整数値のとき」や「a
が整数値でないとき」を表すことができました。
しかし、本当にa
やb
がそうなっているか、実際に何が入っているかはit
の中身を見なければわかりませんでした。
そこでlet
を使ってa
とb
を定義してあげることで見通しを良くします。
RSpec.describe "Calculator" do
describe "#add" do
context "when both a and b are integer" do
let(:a) { 1 }
let(:b) { 2 }
it "returns the sum" do
...
end
end
context "when a is not an integer" do
let(:a) { nil }
let(:b) { 2 }
it "returns nil" do
...
end
end
context "when b is not an integer" do
let(:a) { 1 }
let(:b) { nil }
it "returns nil" do
...
end
end
end
end
a
とb
がcontext
の近くに移動したことで、コンテキストごとの変数の定義が明確になりました。
さらに、上位のブロックで共通のlet
を定義しておくことでもっとシンプルにできます。
下記が完成の形です。
RSpec.describe "Calculator" do
describe "#add" do
let(:a) { 1 }
let(:b) { 2 }
context "when both a and b are integer" do
it "returns the sum" do
calc = Calculator.new
expect(calc.add(a, b)).to eq(a + b)
end
end
context "when a is not an integer" do
let(:a) { nil }
it "returns nil" do
calc = Calculator.new
expect(calc.add(a, b)).to ne_nil
end
end
context "when b is not an integer" do
let(:b) { nil }
it "returns nil" do
calc = Calculator.new
expect(calc.add(a, b)).to be_nil
end
end
end
end
ここではlet
を単純な変数の定義にしか使っていませんが、let
にはブロックの評価をメモ化するという有用な役割があります。
let
のメリットについて詳しくは下記の記事を参照してみてください。
以上です。
このエントリでは、RSpecのletとcontextの使ってテストの見通しを良くする方法を解説しました。
コメントを送る
コメントはブログオーナーのみ閲覧できます