この記事は、Business Bank Group Developers Advent Calendar 12日目の記事です。
前書き
ビジネスロジックのspecを書いている時に、specファイルが肥大化してしまい、メンテナンスが辛くなってきたので、rspec-parameterizedを使ってリファクタリングをしたよ。という話です。
元のspec
このようなspecを書いていました。(本当は、もう少し複雑です)
describe "#validate" do
subject { importer.validate(column_type, condition) }
let(:column_type) { ColumnType.find_by_code(code) }
let(:condition) { setting: setting, amount: amount }
%w(a b c e).each do |code|
context "when column_type is '#{code}'" do
context "when setting is true" do
let(:setting) { true }
context "when amount blank" do
let(:amount) { nil }
it { expect(subject).to eq nil }
end
context "when amount present" do
let(:amount) { 2 }
it { expect(subject).to eq nil }
end
context "when amount is invalid format" do
let(:amount) { "ABC" }
it { expect(subject).to eq "invalid_format" }
end
end
context "when setting is false" do
let(:setting) { false }
context "when amount nil" do
let(:amount) { nil }
it { expect(subject).to eq nil }
end
context "when amount present" do
let(:amount) { 2 }
it { expect(subject).to eq "invalid_setting" }
end
end
end
end
%w(d f).each do |code|
# contexts(長くなるので割愛)
end
end
...条件が増えるごとにcontextを増やさないといけないのでしょうか。書いてて嫌になりそうです(笑)
更に、MECEを考える時にパターンの漏れが発生しやすそうです...
rspec-parameterizedを使ってみた
rspec-parameterizedのNested Array Style
を用いて、このようにリファクタリングできました。
describe "#validate" do
subject { importer.validate(column_type, condition) }
let(:condition) { setting: setting, amount: amount }
let(:column_type) { ColumnType.find_by_code(code) }
%w(a b c e).each do |code|
context "when column_type is '#{code}'" do
where(:setting, :amount, :result) do
[
[true ,nil, nil],
[true ,2, nil],
[true ,"ABC", "invalid_format"],
[false ,nil, nil],
[false ,2, "invalid_setting"],
[false ,"ABC", "invalid_setting"]
]
end
with_them { it { expect(subject).to eq result } }
end
end
%w(d f).each do |code|
# contexts(割愛)
end
end
rspec-parameterizedの書き方については、下記記事でまとめています。
rspec-parameterized ことはじめ
どうなったか
- コードの行数が約1/3に減った
- 行数が減ったことによりコードが見やすくなった
- コードが見やすくなったことにより、specで仕様を表せていることがより可視化できた
まとめ
FizzBuzzなど、簡単なテストであればまだ可愛いですが、実際のビジネスロジックでは、各ステータス(条件)毎の〇〇を求めるメソッドなど、複雑な条件を網羅するテストを書く必要があり、rspec-parameterizedは、それを書きやすく、より分かりやすくさせるものでした!
明日は @Kirika さんが担当です。よろしくお願いします!