重用RSpec行为验证

时间:2012-12-22 17:21:34

标签: ruby-on-rails rspec code-reuse

在我的Rails 3应用程序中,我有一个RSpec规范,用于检查给定字段的行为(用户模型中的角色),以保证该值在有效值列表。

现在,我将为另一个字段提供完全相同的规范,在另一个具有另一组有效值的模型中。我想提取公共代码,而不是仅仅复制和粘贴它,更改变量。

我想知道是否会使用共享示例或其他RSpec重用技术。

以下是相关的RSpec代码:

describe "validation" do  
  describe "#role" do
    context "with a valid role value" do
      it "is valid" do
        User::ROLES.each do |role|
          build(:user, :role => role).should be_valid
        end
      end
    end

    context "with an empty role" do
      subject { build(:user, :role => nil) }

      it "is invalid" do
        subject.should_not be_valid
      end

      it "adds an error message for the role" do
        subject.save.should be_false
        subject.errors.messages[:role].first.should == "can't be blank"
      end
    end

    context "with an invalid role value" do
      subject { build(:user, :role => 'unknown') }

      it "is invalid" do
        subject.should_not be_valid
      end

      it "adds an error message for the role" do
        subject.save.should be_false
        subject.errors.messages[:role].first.should =~ /unknown isn't a valid role/
      end
    end
  end
end

重用此代码的最佳情况是什么,但将角色(正在验证的字段)和 User :: ROLES (有效值的集合)提取到参数传递给这段代码?

2 个答案:

答案 0 :(得分:2)

您可以通过shared_examples技术干这样的规范:

  shared_examples "no role" do
    it "is invalid" do
      subject.should_not be_valid
    end
  end

  context "with an empty role" do
    subject { Factory.build(:user, :name => nil) }
    it_behaves_like "no role"
  end

  context "with an invalid role value" do
    subject { Factory.build(:user, :name => '') }
    it_behaves_like "no role"
  end

但是你干掉几个规格的想法怎么样......我认为这太过分了。我相信规范必须首先是可读的,然后才能干。如果您的规格很少,那么将来阅读/重构/更改此代码可能会令您头疼。

答案 1 :(得分:2)

我认为这是一个非常合理的共享示例用例。例如像这样的东西:

shared_examples_for "attribute in collection" do |attr_name, valid_values|

  context "with a valid role value" do
    it "is valid" do
      valid_values.each do |role|
        build(:user, attr_name => role).should be_valid
      end
    end
  end

  context "with an empty #{attr_name}" do
    subject { build(:user, attr_name => nil) }

    it "is invalid" do
      subject.should_not be_valid
    end

    it "adds an error message for the #{attr_name}" do
      subject.save.should be_false
      subject.errors.messages[attr_name].first.should == "can't be blank"
    end
  end

  context "with an invalid #{attr_name} value" do
    subject { build(:user, attr_name => 'unknown') }

    it "is invalid" do
      subject.should_not be_valid
    end

    it "adds an error message for the #{attr_name}" do
      subject.save.should be_false
      subject.errors.messages[attr_name].first.should =~ /unknown isn't a valid #{attr_name}/
    end
  end
end

然后你可以在你的规范中调用它:

describe "validation" do  
  describe "#role" do
    behaves_like "attribute in collection", :role, User::ROLES
  end
end

没有对此进行测试,但我认为它应该可行。