zkwentz
zkwentz

Reputation: 1105

rspec expectation syntax with validates_associated

New to rspec, and wondering how to write an expectation for validates_associated.

post.rb

class Post
  validates_associated :user
end

post_spec.rb

it 'must belong to a user' do
  post = build(:post, user: nil)
  expect(post).to have(1).errors_on(:user)
end

However this doesn't work, nor does checking for error_on(:user_id)

Upvotes: 0

Views: 1011

Answers (2)

Sachin Singh
Sachin Singh

Reputation: 7225

class Post
  validates_associated :user
end

class User
  validates :name, presence:true
end

Validates associated practically means with example

post = Post.find 1

post.title = "something"
post.user.name =  nil

post.save => false

It returns false as associated user is not valid because user's name is not present.

To test it, you should:

it 'validates associated user' do
  post = build(:post)
  post.user.build(:name => nil)
  post.save.should == false
  post.user.errors.should == {:name => [name must be present]} // something like this
end

Upvotes: 1

Peter Alfvin
Peter Alfvin

Reputation: 29419

There are lots of ways to use RSpec, particularly in light of the recent transition from the should to expect approach. In this answer, I'll try to respond to why your test isn't working as is, assuming that build called with those particular arguments would indeed raise the error you say it should. In other words, I'll try to respond to the form of your test.

First, I'm not sure what you intended with your statement post = build(...). If you intended to actually execute the build method at that point and you expect the execution of build to fail, that's going to cause your test to fail. To test the raising of an error, you need to pass the code which is going to raise the error to RSpec and let RSpec invoke it. In general, you want to set expectations before executing the code under test.

If you expected post = build(...) to be defining post as a function to invoke build, that's not the right syntax. If you wanted to use this approach, you'd have to say post = lambda {build(...)}. That would allow the expect method to execute post and examine what errors are raised by it.

Alternatively, you can pass a block directly to expect, as in:

expect{build(...)}.to ...

See https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/expect-error for more examples.

Upvotes: 0

Related Questions