Reputation: 3345
I have the following Rspec test for a vote model, which includes a custom validation ensuring you can't vote on your own content, which is shown below. I am puzzled as to why only 2 of these tests fail with a nilclass error when the other tests within the spec pass.
@vote must be nil but why aren't the other tests failing with the same error?
vote.rb
validates :ensure_not_author
def ensure_not_author
votable = self.votable_type.downcase
errors.add(:user_id, "You can't vote on your own content.") if self.votable.user_id == self.user_id
end
factories
factory :answer do
user_id :user
question_id :question
body "you need to change your grip"
votes_count 0
correct false
end
factory :vote do
user_id :user
votable_id :answer
votable_type "Answer"
value 1
points 5
end
factory :user do |u|
u.sequence(:email) {|n| "test#{n}@hotmail.com"}
u.sequence(:username) {|n| "tester#{n}" }
u.password "password"
u.password_confirmation "password"
u.remember_me true
u.reputation 200
end
vote_spec.rb
require "spec_helper"
describe Vote do
before(:each) do
@user2 = FactoryGirl.create(:user)
@user = FactoryGirl.create(:user)
@answer = FactoryGirl.create(:answer, user_id: @user)
@vote = Vote.create(user_id: @user2.id, value: 1, points: 5, votable_id: @answer.id, votable_type: "Answer")
end
subject { @vote }
it { should respond_to(:user_id) }
it { should respond_to(:votable_id) }
it { should respond_to(:votable_type) }
it { should respond_to(:value) }
it { should respond_to(:points) }
describe 'value' do
before { @vote.value = nil }
it { should_not be_valid }
end
describe "user_id" do
before { @vote.user_id = nil }
it { should_not be_valid }
end
describe "votable_id" do
before { @vote.votable_id = nil }
it { should_not be_valid }
end
describe "votable type" do
before { @vote.votable_type = nil }
it { should_not be_valid }
end
describe "vote value" do
before { @vote.value = 5 }
it { should_not be_valid }
end
end
Failures:
1) Vote votable_id
Failure/Error: it { should_not be_valid }
NoMethodError:
undefined method `user_id' for nil:NilClass
# ./app/models/vote.rb:17:in `ensure_not_author'
# ./spec/models/vote_spec.rb:25:in `block (3 levels) in <top (required)>'
2) Vote votable type
Failure/Error: it { should_not be_valid }
NoMethodError:
undefined method `downcase' for nil:NilClass
# ./app/models/vote.rb:16:in `ensure_not_author'
# ./spec/models/vote_spec.rb:35:in `block (3 levels) in <top (required)>'
Upvotes: 1
Views: 273
Reputation: 14082
You validator ensure_not_author
depends Vote#votable_type
and Vote#votable
to function well. And when you test validity of @vote
, this validator will be tested.
However, in your "votable_id"
testcase, you set votable_id
to be nil
. Later when you test @vote
's validity with should_not be_valid
, the ensure_not_author
is called and failed at self.votable.user_id
because ActiveRecord will query for Votable
with votable_id
.
Similarly, your "votable type"
test case failed at self.votable_type.downcase
since you set votable_type
to be nil
.
You should check the availability of the attributes in your validator before you send messages to them. Or write other validators to check them before ensure_not_author
.
Upvotes: 2