Rspec validates_uniqueness_of test failing with ad

2019-05-31 01:06发布

问题:

I have 2 scoped uniqueness validations on my answer model, I am trying to test these using Rspec and the respective shoulda matchers.

As seen in the test trace below, the uniqueness validations message is present in the errors array however, there are also 2 and sometimes 3 other errors present; "body can't be blank (nil)", "body is too short (minimum is 10 characters) (nil)", "user_id can't be blank (nil)". I'm not sure where they are coming from, as body and user attributes are set explicitly in the before block.

How can I correct these additional errors so the uniqueness test will pass?

answer.rb

    validates_uniqueness_of :correct, scope: :question_id, if: :correct?, message: "You can only have 1 correct answer per question"
    validates_uniqueness_of :user_id, scope: :question_id, message: "Only 1 answer per question per user"

    /* omitted for brevity */

answer_spec.rb

require "spec_helper"

describe Answer do  
  before(:each) do
    @user1 = create(:user)
    @answer = create(:answer, correct: true, user_id: @user1.id, body: "some text which is over 10 chars long")
  end

  subject { @answer }

  it { should respond_to(:user_id) }
  it { should respond_to(:question_id) }
  it { should respond_to(:body) }
  it { should respond_to(:correct)}
  it { should respond_to(:votes_count)}
  it { should respond_to(:points)}
  it { should belong_to(:question)}
  it { should belong_to(:user)}
  it { should have_many(:activities)}
  it { should have_many(:comments)}
  it { should have_many(:votes)}
  it { should validate_uniqueness_of(:correct).scoped_to(:question_id).with_message("correct You can only have 1 correct answer per question (true)") }
  it { should validate_uniqueness_of(:user_id).scoped_to(:question_id).with_message("user_id Only 1 answer per question per user (1)") }

/* omitted for brevity */

Test trace

  1) Answer 
     Failure/Error: it { should validate_uniqueness_of(:correct).scoped_to(:question_id).with_message("correct You can only have 1 correct answer per question (true)") }
       Expected errors to include "correct You can only have 1 correct answer per question (true)" when correct is set to true, got errors: ["body can't be blank (nil)", "body is too short (minimum is 10 characters) (nil)", "user_id can't be blank (nil)", "correct You can only have 1 correct answer per question (true)"]
     # ./spec/models/answer_spec.rb:20:in `block (2 levels) in <top (required)>'

  2) Answer 
     Failure/Error: it { should validate_uniqueness_of(:user_id).scoped_to(:question_id).with_message("user_id Only 1 answer per question per user (1)") }
       Expected errors to include "user_id Only 1 answer per question per user (1)" when user_id is set to 1, got errors: ["body can't be blank (nil)", "body is too short (minimum is 10 characters) (nil)", "user_id Only 1 answer per question per user (1)"]
     # ./spec/models/answer_spec.rb:21:in `block (2 levels) in <top (required)>'

Finished in 1.31 seconds
17 examples, 2 failures

factory.rb

factory :answer do
    user
    question_id :question
    body "you need to change your grip"
    votes_count 0
    correct false
  end

回答1:

It's failing because you're not testing @answer. You're not defining your subject in these tests. So it's using rspec's subject which by default is going to a new instance of whatever class you're describing, ie. Answer.new. You either need to explicitly set the subject to @answer or explicitly test @answer.

describe Answer do
  it { should validate_uniqueness_of(:correct).scoped_to(:question_id).with_message("correct You can only have 1 correct answer per question (true)") }
  it { should validate_uniqueness_of(:user_id).scoped_to(:question_id).with_message("user_id Only 1 answer per question per user (1)") }
end