RSpecの難しさ

RSpecの文法に触れる機会が多いのであれこれこねくり回している。

def hoge(key)
  {a: "AAA", b: "BBB", c: "CCC"}[key]
end

のテストをどう書く?

一つのit にまとめて should
describe "#hoge" do
  it "hoge がなんか返す" do
    hoge(:a).should == "AAA"
    hoge(:b).should == "BBB"
    hoge(:c).should == "CCC"
    hoge(:d).should be_nil
  end
end
it を分割
describe "#hoge" do
  it "keyが :aの場合は AAAを返す" do
    hoge(:a).should == "AAA"
  end

  it "keyが :bの場合は BBBを返す" do
    hoge(:b).should == "BBB"
  end

  it "keyが :cの場合は CCCを返す" do
    hoge(:c).should == "CCC"
  end

  it "keyが :dの場合は nilを返す" do
    hoge(:d).should be_nil
  end
end
配列で データドリブンテスト
describe "#hoge" do
  [["keyが :aの場合は AAAを返す", :a, "AAA"],
   ["keyが :bの場合は BBBを返す", :b, "BBB"],
   ["keyが :cの場合は CCCを返す", :c, "CCC"],
   ["keyが :dの場合は nilを返す", :d, nil],
  ].each do |desc, input, expected|
    it desc do
      hoge(input).should == expected
    end
  end
end
subject & context
describe "#hoge" do
  subject { hoge(fuga_key) }

  context "keyが :aの場合は AAAを返す" do
    let(:fuga_key) { :a }
    it { should == "AAA" }
  end

  context "keyが :bの場合は BBBを返す" do
    let(:fuga_key) { :b }
    it { should == "BBB" }
  end

  context "keyが :cの場合は CCCを返す" do
    let(:fuga_key) { :c }
    it { should == "CCC" }
  end

  context "keyが :dの場合は nilを返す" do
    let(:fuga_key) { :d }
    it { should be_nil }
  end
end
shared_context
shared_context "subject" do
  subject{hoge(key)}
end

describe "#hoge" do
  include_context "subject"

  context ":a なら AAA" do
    let(:key){:a}
    it{ should == "AAA"}
  end

  context ":b なら BBB" do
    let(:key){:b}
    it{ should == "BBB"}
  end

  context ":c なら CCC" do
    let(:key){:c}
    it{ should == "CCC"}
  end

  context ":d なら nil" do
    let(:key){:d}
    it{ should be_nil }
  end
end
shared_examples
shared_examples "#hoge はなんか返す" do
  subject{hoge(key)}
  it{ should == expected }
end

describe "#hoge" do
  context ":a なら AAA" do
    let(:key){:a}
    let(:expected){"AAA"}
    it_behaves_like "#hoge はなんか返す"
  end

  context ":b なら BBB" do
    let(:key){:b}
    let(:expected){"BBB"}
    it_behaves_like "#hoge はなんか返す"
  end

  context ":c なら CCC" do
    let(:key){:c}
    let(:expected){"CCC"}
    it_behaves_like "#hoge はなんか返す"
  end

  context ":d なら nil" do
    let(:key){:d}
    let(:expected){nil}
    it_behaves_like "#hoge はなんか返す"
  end
end

今回のケースだとshared_context、shared_examplesはやらないだろうが、
たった3行メソッドでも書き方がいろいろ考えられる。
RSpecの欠点は、選択肢の多さだろう。学習コストは高い。

追記

後輩から突っ込みが。

def hoge(key)
  {a: "AAA", b: "BBB", c: "CCC"}[key]
end

このメソッドに意図が不明確で解りにくいから、迷うのでは? メソッドを書き換えて、その意図が伝わるように、 describe context subject等をうまく使ってメソッドの意図を捕捉するのでは?
(あるいは順序は逆転して、RSpecの記述で describe context subject等を駆使して考えながら記述することで、
メソッドの意図を明確になるように書き換えるのでは?)、とのフィードバック。

それは確かに一理ある。8割5分同意。1割5分 同意せずかな。
後で書く。