For my Rails 3 application I use FactoryGirl together with shoulda context (1.0.0.beta1) and matchers (1.0.0.beta3) for my functional tests. My problem: in the code example below, the assign_to test fails because @user - to my surprise - turns out to be nil. In the outer setup block, @user is开发者_如何学JAVA assigned a valid model instance, but from within the should assign_to statement the instance variable is not accessible. Why is that and what is the correct way to write that test?
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
@user = Factory.create(:user)
end
context "getting index" do
setup do
get :index
end
should assign_to(:users).with([@user])
end
end
I discovered that passing the value as a black miraculously works. However, after digging into the actual AssignToMatcher code, it doesn't seem to make sense why the parameter method wouldn't work while the block method would.
For the sake of the +250 rep I'm investing in this, I'd still like an answer that explains why the param method isn't working (and how to fix it), but until then, at least I have a workaround.
@dblp1, hopefully this works for you too. Here's an example specific to your code:
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
@user = Factory.create(:user)
end
context "getting index" do
setup do
get :index
end
should assign_to(:users).with { [@user] }
end
end
end
(I am pasting as an answer as it is fairly long)
I mocked a bit your test and checked what was the results passed.
Interestingly enough, when I call the matcher @post=null
(as I believe in your case). The issues I think (after a while of investigation), it coming from the the order the setup do
block is called and the fact that the variables defined in one context are not visible in the nested context.
modified class
context "as admin" do
setup do
@post = Post.new
puts "Step 1 - inside setup do"
puts @post.class
end
puts "Step 2 - outside setup do 1"
puts @post.class
context "getting index" do
setup do
get :index
end
puts "Step 3 - calling shoulda"
puts @post.class
should assign_to(:posts).with([@post])
#should assign_to(:posts).with { [@post] }
end
end
And the results in the console
ruby -I test test/functional/posts_controller_test.rb
Step 2 - outside setup do 1
NilClass
Step 3 - calling shoulda
NilClass
Loaded suite test/functional/posts_controller_test
Started
Step 1 - inside setup do
Post
So the setup cycle is called at the end (and not at the beginning) and then your is Nil when passed to the matcher.
Even if I remove the first setup do
does not work pretty well.
Step 1 - inside setup do
Post
Step 2 - outside setup do 1
Post
Step 3 - calling shoulda
NilClass
Finally, putting the post in the inner context
Step 3 - calling shoulda
Post
If you call @user = Factory.create(:user)
directly inside the "getting index" context, I believe it will work.
When you are working with indexes you should use the plural of the instance variable.
@users
rather than @user
You should also populate it as an array.
Finally, Shoulda matchers should start with "it" and be contained in braces, at least in the RSpec world, which is what I use. Not sure if this is the case with Test::Unit or whether your formatting above will work.
Try something like this.
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
@user = Factory.create(:user)
end
context "getting index" do
setup do
@users = Array.new(3) { Factory(:user) }
get :index
end
it { should assign_to(:users).with(@users) }
end
end
精彩评论