简体   繁体   English

我该如何删除应试中的重复项?

[英]How do I remove duplication in shoulda tests?

Here is what I have: 这是我所拥有的:

   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

Clearly there is a lot of duplication there. 显然那里有很多重复。 Any thoughts on how to remove it, if only at the very least the context and the string? 如果至少将上下文和字符串删除,是否有任何关于如何删除它的想法?

Here's a solution to your specific problem. 这是您特定问题的解决方案。 The idea is to create a class method (like Shoulda's context, setup and should). 这个想法是创建一个类方法(如Shoulda的上下文,设置和应该)。

Encapsulate the repetition in a class method accepting all varying parts as arguments like this: 将重复封装在一个接受所有不同部分作为参数的类方法中,如下所示:

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

Now you can call all these encapsulated tests with one liners (5-liners here for readability ;-) 现在,您可以使用一个衬管调用所有这些封装的测试(此处为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

In some cases, you may want to accept a block which could serve as your Shoulda setup. 在某些情况下,您可能希望接受可以用作Shoulda设置的块。

Duplication in tests is not necessarily a Bad Thing(tm) 测试中的重复不一定是一件坏事(tm)

I suggest you read the following articles from Jay Field 我建议您阅读Jay Field的以下文章

http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html 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 http://blog.jayfields.com/2008/05/testing-duplicate-code-in-your-tests.html

They make a convinving case for code duplication in the tests and keeping one assertion per test. 他们为测试中的代码重复提供了令人信服的理由,并为每个测试保留了一个断言。

Tests/specs are not production code and so being dry is not a priority. 测试/规格不是生产规范,因此干燥不是重点。

The principle is that the specs should be clear to read, even if it means there is duplication of text across tests. 原则是规范应该易于阅读,即使这意味着测试之间文本重复。

Don't be too concerned about specs being dry. 不必太担心规格干燥。 Overemphasis of dry tests tends to make things more difficult as you have to jump around to the definitions of things to understand what is happening. 过于强调干式测试会使事情变得更加困难,因为您必须跳到事物的定义以了解正在发生的事情。

Personally for this test, I wouldn't use Shoulda. 就个人而言,我不会使用Shoulda。 You can easily remove duplication by using dynamic method creation as follows: 您可以使用动态方法创建轻松地删除重复项,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM