当前位置: 动力学知识库 > 问答 > 编程问答 >

ruby - How to DRY up RSpec tests for Rails

问题描述:

I'm learning RSpec and I can't help but notice there's a lot of duplication in my code. The following are just two examples of many others. Is there a way to create a shared test without having to go through every individual attribute?

 describe "validation" do

describe "user_id" do

it "should not be blank or nil" do

@comment.user_id = nil

@comment.should_not be_valid

@comment.user_id = " "

@comment.should_not be_valid

end

it "should an integer" do

@comment.user_id = "a"

@comment.should_not be_valid

end

end

describe "post_id" do

it "should not be blank or nil" do

@comment.post_id = nil

@comment.should_not be_valid

@comment.post_id = " "

@comment.should_not be_valid

end

it "should an integer" do

@comment.post_id = "a"

@comment.should_not be_valid

end

end

end

网友答案:

In the first describe block you can set the subject to @comment.user_id like so:

describe "validation" do
  describe "user_id" do
    before { @comment = Comment.create } # or however you want to initialize your comment     
                                         # (FactoryGirl is commonly used)
    subject { @comment.user_id }

    it "should not be blank or nil" do
      before { @comment.user_id = nil }           #I edited this to make it clearer.
      it { should_not be_valid }

      before { @comment.user_id = " " }
      it { should_not be_valid }
    end
    ...

This dries it up some and makes it a little more readable I think. Obviously you can pattern the rest off of what I have here.


EDIT: This doesn't save many characters (in fact you're typing more in the end), but it does eliminate the duplication of @comment.{attrbute} = whatever in the spec file itself. You can define a helper for each assignment, like follows:

/spec/helpers/comment_spec_helper.rb
def user_id nil
  @comment.user_id = nil
end

....

And do that for each attribute. Then in your spec:

    subject { @comment.user_id }

    it "should not be blank" do
      before { user_id nil }         
      it { should_not be_valid }

    it "should not be nil" do
     ...

The downside is, you'll have to do that for each attribute in the helper, and in the end you're doing a little more work. But if your primary concern is eliminating duplication in the spec file, this will help.

I don't know how idiomatic this is. I generally initiate new objects in the spec file for validation testing, (and my spec_helper normally handles multiple-step processes like clicking drop-downs, filling in text, then clicking "submit") but maybe you have more validations than I typically have.


UPDATE

I was working on a project and just flipped through notes from Codeschool's RSpec course that I took, and I thought I'd suggest shared examples. The example they give is:

describe Zombie do
  it_behaves_like ‘the undead’, Zombie.new
end

describe Vampire do
  it_behaves_like ‘the undead’, Vampire.new
end

shared_examples_for ‘the undead’ do |undead|
  it ‘does not have a pulse’ do
    undead.pulse.should == false
  end
end

This seems applicable, though you would have to keep in mind certain conventions to ensure your shared examples are loaded.

This would really DRY up your code, but I personally would be a little concerned about readability. I suppose if you use a descriptive-enough name for your shared examples you'll be fine.

网友答案:

You can try this: https://github.com/thoughtbot/shoulda-matchers

It gives you a lot of simple matchers for your model

网友答案:

You could use factories (e.g. FactoryGirl):

build(:comment, user_id: nil).should_not be_valid
分享给朋友:
您可能感兴趣的文章:
随机阅读: