为什么控制器应该测试 allocate_to 无法访问实例变量?

发布于 2024-12-04 10:15:36 字数 539 浏览 1 评论 0原文

对于我的 Rails 3 应用程序,我将 FactoryGirl 与 Shoulda 上下文 (1.0.0.beta1) 和匹配器 (1.0.0.beta3) 一起使用来进行功能测试。 我的问题:在下面的代码示例中, allocate_to 测试失败,因为 @user - 令我惊讶的是 - 结果为零。在外部设置块中,@user 被分配了一个有效的模型实例,但从should allocate_to 语句中无法访问实例变量。这是为什么?编写该测试的正确方法是什么?

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

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 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

熊抱啵儿 2024-12-11 10:15:36

我发现以黑人的身份传递价值奇迹般地有效。但是,在深入研究实际的 AssignToMatcher 代码之后,为什么参数方法不起作用而块方法却起作用,这似乎没有意义。

为了获得 +250 代表,我对此进行了投资,我仍然想要一个答案来解释为什么 param 方法不起作用(以及如何修复它),但在那之前,至少我有一个解决方法。

@dblp1,希望这也适合你。这是一个特定于您的代码的示例:

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 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
随梦而飞# 2024-12-11 10:15:36

(我粘贴作为答案,因为它相当长)

我嘲笑了你的测试并检查了通过的结果。

有趣的是,当我调用匹配器 @post=null (正如我相信你的情况一样)。我认为的问题(经过一段时间的调查),它来自于 setup do 块的调用顺序以及在一个上下文中定义的变量在嵌套上下文中不可见的事实。

修改后的类

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

和控制台中的结果

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

因此,设置周期在结束时(而不是在开始时)被调用,然后当传递给匹配器时,您的值为 Nil 。

即使我删除第一个setup也不能很好地工作。

Step 1 - inside setup do
Post
Step 2 - outside setup do 1
Post
Step 3 - calling shoulda
NilClass

最后,将帖子放在内部上下文中

Step 3 - calling shoulda
Post

如果您直接在“获取索引”上下文中调用 @user = Factory.create(:user) ,我相信它会起作用。

(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.

心凉怎暖 2024-12-11 10:15:36

当您使用索引时,您应该使用实例变量的复数。

@users 而不是 @user

您还应该将其填充为数组。

最后,应该匹配器应该以“it”开头并包含在大括号中,至少在我使用的 RSpec 世界中是这样。不确定 Test::Unit 是否属于这种情况,或者您上面的格式是否有效。

尝试这样的事情。

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文