Reputation: 3659
Have simple test:
context "in the same board" do
@link = FactoryGirl.create(:link_with_board, url: "www.onet.pl")
@board = @link.board
it "is invalid when the same url already exists" do
expect(@board.links.build(url: "www.onet.pl")).to_not be_valid
expect(@board.links.build(url: "http://www.onet.pl")).to_not be_valid
expect(@board.links.build(url: "www.onet.pl/")).to_not be_valid
end
end
It shows me error:
Failures:
1) Link in the same board is invalid when the same url already exists
Failure/Error: expect(@board.links.build(url: "www.onet.pl")).to_not be_valid
NoMethodError:
undefined method `links' for nil:NilClass
# ./spec/models/link_spec.rb:50:in `block (3 levels) in <top (required)>'
When I try the same in console, it all works fine. Any idea why?
Update:
Ok, I made it work, but still question remains the same, why the first one didn't work?
context "in the same board" do
#FIX START
before :each do
@link = FactoryGirl.create(:link_with_board, url: "www.onet.pl")
@board = @link.board
end
#FIX END
it "is invalid when the same url already exists" do
expect(@board.links.build(url: "www.onet.pl")).to_not be_valid
expect(@board.links.build(url: "http://www.onet.pl")).to_not be_valid
expect(@board.links.build(url: "www.onet.pl/")).to_not be_valid
end
end
Upvotes: 0
Views: 94
Reputation: 30023
You are setting up @link
and @board
in a context
block. This is a different scope to the it
block, so when the it
block runs those variables aren't defined.
Behind the scenes, context
creates a class and it
creates a method, so what you were doing was something similar to this:
class MyExampleGroup
@link = FactoryGirl.create(:link_with_board, url: "www.onet.pl")
@board = @link.board
def it_is_invalid_sometimes
@board.nil? # => true
end
end
An instance variable set in class scope is visible in the class, but not in instances of the class.
When you moved them to before, the generated structure was more like this:
class MyExampleGroup
def before
@link = FactoryGirl.create(:link_with_board, url: "www.onet.pl")
@board = @link.board
end
def it_is_invalid_sometimes
@board.nil? # => false
end
end
Now the instance variables are being defined in instance scope, so they work as you expect.
(I'm simplifying slightly for clarity: The methods created by it
calls actually return RSpec::Core::Example
objects, and the before
blocks are run on those objects using instance_exec
.)
Upvotes: 3
Reputation: 6823
If you start the console with a simple rails console
command, it connects to the development database (in a normal setup). But the tests are run against the test database.
In your test, the line creating the @link
:
@link = FactoryGirl.create(:link_with_board, url: "www.onet.pl")
You might want to check how the :link_with_board
factory is defined. (Probably in spec/factories/*.rb
.)
Upvotes: 1