Louis Morin
Louis Morin

Reputation: 149

Rspec failure - validation

When I run the following command rspec spec/models/vote_spec.rb, I get the following error:

Failures:

  1) Vote validations value validation only allows -1 or 1 as values
     Failure/Error: expect ( @post.votes ).to eq(-1)
     NoMethodError:
       undefined method `votes' for nil:NilClass
     # ./spec/models/vote_spec.rb:7:in `block (4 levels) in <top (required)>'

Finished in 0.00255 seconds (files took 2.37 seconds to load)
1 example, 1 failure

Here's my code for vote_spec.rb

require 'rails_helper'

describe Vote do
  describe "validations" do
    describe "value validation" do
      it "only allows -1 or 1 as values" do
        expect ( @post.votes ).to eq(-1)
        expect ( @post.votes ).to eq(1)
      end
    end
  end
end

Sorry I am new to this, I guess my @post variable is not being set. Where should I look for this?

Upvotes: 1

Views: 284

Answers (2)

Sasha
Sasha

Reputation: 6466

Correct. You're running into this error because your @post variable is nil. What do you mean by "where should I look for this?"

In order to fix this error, you need to define @post somehow in your spec, above the two "examples" in your it block. (This could go in the it block, or in a describe or let block above the it). Two options. Create the object long-form:

@post = Post.create(attribute_hash_here)

or use a factory of some sort (example below uses FactoryGirl):

@post = create(:post)

As it stands, however, were you to do that, your spec would still fail, because it has contrasting expectations:

expect ( @post.votes ).to eq(-1)
expect ( @post.votes ).to eq(1)

Unless the votes method on Post both returns a value AND alters that value, @post.votes will equal EITHER -1 or 1. So if it passes the first expectation, it will fail the second, and if it passes the second, it will fail the first.

** EDIT ** -- As ChrisBarthol pointed out, it's not clear why you need @post to exist at all. If you're just testing a vote's attribute validations, why not just test that object on its own?

Upvotes: 3

ChrisBarthol
ChrisBarthol

Reputation: 4959

First off these are model validations, and you are validating the vote model not the post model, so you should be setting @vote, and not @post. Secondly your test says you expect the value to equal -1 and then 1. How could it be both at the same time? Where are you setting the value such that you expect it? You have to restructure you tests so you are only testing one item at a time.

require 'rails_helper'

describe Vote do

    let(:post) { Post.new(whatever post params) }
    before { @vote=post.votes.build(whatever vote parameters you have) }

    subject { @vote }

    describe "validations" do
        describe "+1 value valdiation" do
            before { @vote.value = 1 }
            it { should be_valid }
        end
        describe "-1 value valdiation" do
            before { @vote.value = -1 }
            it { should be_valid }
        end
        describe "other value valdiation" do
            before { @vote.value = 0 }
            it { should_not be_valid }
        end
    end
end

I'm guessing at your relationships. There are also better ways to write these tests but that should lead you down the right road.

Upvotes: 2

Related Questions