5

在我的 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(有效值的集合)提取到传递给此代码的参数中?

4

2 回答 2

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

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

于 2012-12-22T17:46:07.003 回答
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

尚未对此进行测试,但我认为它应该可以工作。

于 2012-12-23T16:38:47.093 回答