Как мне удалить дубликаты в тестах должны? - PullRequest
2 голосов
/ 22 сентября 2008

Вот что у меня есть:

   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

Очевидно, что там много дублирования. Любые мысли о том, как удалить его, если хотя бы контекст и строку?

Ответы [ 4 ]

4 голосов
/ 22 сентября 2008

Вот решение вашей конкретной проблемы. Идея состоит в том, чтобы создать метод класса (например, контекст, настройка и необходимость Следует).

Инкапсулируйте повторение в методе класса, принимая все переменные части в качестве аргументов, подобных этому:

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

Теперь вы можете вызывать все эти инкапсулированные тесты с одним вкладышем (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

В некоторых случаях вы можете захотеть принять блок, который может служить вашей настройкой Следует.

2 голосов
/ 22 сентября 2008

Дублирование в тестах не обязательно плохо (тм)

Предлагаю вам прочитать следующие статьи от Джея Филда

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 голос
/ 23 сентября 2008

Тесты / спецификации не являются рабочим кодом, и поэтому сухость не является приоритетом.

Принцип заключается в том, что спецификации должны быть четкими для чтения, даже если это означает, что в тестах дублируется текст.

Не беспокойтесь о том, что спецификации сухие. Чрезмерное внимание к сухим тестам, как правило, усложняет ситуацию, так как вам приходится переходить к определениям вещей, чтобы понять, что происходит.

0 голосов
/ 22 сентября 2008

Лично для этого теста я бы не стал использовать Следует. Вы можете легко удалить дублирование с помощью создания динамического метода следующим образом:

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
...