shoulda テストで重複を削除するにはどうすればよいですか?
-
02-07-2019 - |
質問
私が持っているものは次のとおりです。
context "Create ingredient from string" do
context "1 cups butter" do
setup do
@ingredient = Ingredient.create(:ingredient_string => "1 cups butter")
end
should "return unit" do
assert_equal @ingredient.unit, 'cups'
end
should "return amount" do
assert_equal @ingredient.amount, 1.0
end
should "return name" do
assert_equal @ingredient.name, 'butter'
end
end
context "1 (18.25 ounce) package devil's food cake mix with pudding" do
setup do
@ingredient = Ingredient.create(:ingredient_string => "1 (18.25 ounce) package devil's food cake mix with pudding")
end
should "return unit" do
assert_equal @ingredient.unit, '(18.25 ounce) package'
end
should "return amount" do
assert_equal @ingredient.amount, 1.0
end
should "return name" do
assert_equal @ingredient.name, 'devil\'s food cake mix with pudding'
end
end
end
明らかに重複がたくさんあります。少なくともコンテキストと文字列だけを削除する方法について何か考えはありますか?
解決
ここでは、特定の問題に対する解決策を示します。アイデアは、クラス メソッド (Shoulda の context、setup、および should など) を作成することです。
次のように、すべての可変部分を引数として受け入れるクラス メソッドで繰り返しをカプセル化します。
def self.should_get_unit_amount_and_name_from_string(unit, amount, name, string_to_analyze)
context string_to_analyze do
setup do
@ingredient = Ingredient.create(:ingredient_string => string_to_analyze)
end
should "return unit" do
assert_equal @ingredient.unit, unit
end
should "return amount" do
assert_equal @ingredient.amount, amount
end
should "return name" do
assert_equal @ingredient.name, name
end
end
end
これで、これらのカプセル化されたテストをすべて 1 つのライナーで呼び出すことができます (読みやすくするために、ここでは 5 ライナーで示しています ;-)
context "Create ingredient from string" do
should_get_unit_amount_and_name_from_string(
'cups',
1.0,
'butter',
"1 cups butter")
should_get_unit_amount_and_name_from_string(
'(18.25 ounce) package',
1.0,
'devil\'s food cake mix with pudding',
"1 (18.25 ounce) package devil's food cake mix with pudding")
end
場合によっては、Shoulda セットアップとして機能するブロックを受け入れたい場合があります。
他のヒント
テストでの重複は必ずしも悪いことではありません(tm)
Jay Field による次の記事を読むことをお勧めします。
http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html
http://blog.jayfields.com/2008/05/testing-duplicate-code-in-your-tests.html
彼らは、テスト内のコードの重複と、テストごとに 1 つのアサーションを維持するための説得力のある主張を行っています。
テスト/仕様は製品コードではないため、ドライであることは優先事項ではありません。
原則として、たとえテスト間でテキストの重複があるとしても、仕様は読みやすくなければなりません。
仕様が無味乾燥であることをあまり心配する必要はありません。ドライテストを強調しすぎると、何が起こっているのかを理解するために物事の定義を飛び回らなければならないため、物事がより困難になる傾向があります。
個人的には、このテストでは Shoulda を使用しません。次のように動的メソッド作成を使用すると、重複を簡単に削除できます。
class DefineMethodTest < Test::Unit::TestCase
[{:string => '1 cups butter', :unit => 'cups', :amount => 1.0, :name => 'butter'},{:string => '1 (18.25 ounce) package devil's food cake mix with pudding', :unit => '(18.25 ounce) package', :unit => 1.0, :name => "devil's food cake mix with pudding"}].each do |t|
define_method "test_create_ingredient_from_string_#{t[:string].downcase.gsub(/[^a-z0-9]+/, '_')}" do
@ingredient = Ingredient.create(:ingredient_string => t[:string])
assert_equal @ingredient.unit, t[:unit], "Should return unit #{t[:unit]}"
assert_equal @ingredient.amount, t[:amount], "Should return amount #{t[:amount]}"
assert_equal @ingredient.name, t[:name], "Should return name #{t[:name]}"
end
end
end