Come rimuovo la duplicazione nei test shoulda?
-
02-07-2019 - |
Domanda
Ecco quello che ho:
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
Chiaramente ci sono molte duplicazioni lì. Qualche idea su come rimuoverlo, se non altro il contesto e la stringa?
Soluzione
Ecco una soluzione al tuo problema specifico. L'idea è quella di creare un metodo di classe (come il contesto, l'installazione e dovrebbe di Shoulda).
Incapsula la ripetizione in un metodo di classe accettando tutte le parti variabili come argomenti come questo:
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
Ora puoi chiamare tutti questi test incapsulati con una linea (5 linee qui per leggibilità ;-)
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
In alcuni casi, potresti voler accettare un blocco che potrebbe fungere da configurazione di Shoulda.
Altri suggerimenti
La duplicazione nei test non è necessariamente una cosa negativa (tm)
Ti suggerisco di leggere i seguenti articoli da Jay Field
http://blog.jayfields.com /2007/06/testing-one-assertion-per-test.html
http: //blog.jayfields .com / 2008/05 / test-duplicate-codice-a-la-tests.html
Fanno un caso convincente per la duplicazione del codice nei test e mantengono un'asserzione per test.
I test / le specifiche non sono codici di produzione e quindi essere asciutti non è una priorità.
Il principio è che le specifiche dovrebbero essere chiare da leggere, anche se ciò significa che c'è una duplicazione del testo attraverso i test.
Non preoccuparti troppo del fatto che le specifiche siano asciutte. L'eccessiva enfasi dei test a secco tende a rendere le cose più difficili poiché devi saltare alle definizioni delle cose per capire cosa sta succedendo.
Personalmente per questo test, non avrei usato Shoulda. Puoi rimuovere facilmente la duplicazione usando la creazione dinamica del metodo come segue:
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