如何在控制器中测试实例变量?

How do I test an instance variable in a controller?

我的几位导师告诉我要用控制器规范测试一段代码,即使某些请求规范正在测试内容。我想知道我是否可以测试 @user 这样的实例变量是否可以从 rspec 控制器测试中设置为 someObjectnil

到目前为止,我已经尝试了几种不同的方法来对此进行测试,但我的 rspec 测试技能至少可以说是初级的。我尝试的第一件事是模拟 current_user 和 'User.get_from_auth_user(current_user)。模拟对象打印良好并输出。问题是...我想说 expect(@user).to equal(mockedUser) 之类的话,但这似乎永远行不通。我总是得到类似的东西:

Expect does not equal received
expected is nil
received is { someMockedObject }

这是我要测试的代码。

class ApplicationController < ActionController::Base
  before_action :set_user

  def set_user
    return if current_user.nil?

    @user = User.get_from_auth_user(current_user)
  end
end

我想知道我走的路是否正确,或者什么是完全测试这段代码的更好选择。我觉得答案应该很简单。

使用assigns(:user)获取实例变量@user。在您的规范中,@user 是该测试上下文中的一个变量,它与控制器中的 @user 不同。

https://relishapp.com/rspec/rspec-rails/docs/controller-specs

此外 and answers, it worth to mention in order to use assigns in your specs, you need to set up rails-controller-testing gem, because assigns 从 Rails 5.

开始弃用
# File actionpack/lib/action_dispatch/testing/test_process.rb, line 6
def assigns(key = nil)
  raise NoMethodError,
    "assigns has been extracted to a gem. To continue using it,
    add `gem 'rails-controller-testing'` to your Gemfile."
end

控制器测试用例如下所示

describe 'GET #set_user' do
  let!(:mock_user) { 
      @mockuserObj = { id: 1, name: "username" }
  }
  before(:each) do
    controller.instance_variable_set(:current_user, @mockuserObj)
    get :set_user
  end
  context 'when current_user is present' do
    it "sets the current user" do
      expect(assigns(:user)).to eq(@mockuserObj)
    end
  end
end

你的导师很愚蠢。虽然了解控制器规范可能很好,因为它们在遗留应用程序中无处不在,但将它们添加到新应用程序并不是一个好的做法。

For new Rails apps: we don't recommend adding the rails-controller-testing gem to your application. The official recommendation of the Rails team and the RSpec core team is to write request specs instead. Request specs allow you to focus on a single controller action, but unlike controller tests involve the router, the middleware stack, and both rack requests and responses. This adds realism to the test that you are writing, and helps avoid many of the issues that are common in controller specs.

DHH 很好地解释了测试控制器的实例变量有什么问题以及您应该做什么:

Testing what instance variables are set by your controller is a bad idea. That's grossly overstepping the boundaries of what the test should know about. You can test what cookies are set, what HTTP code is returned, how the view looks, or what mutations happened to the DB, but testing the innards of the controller is just not a good idea.

这就是 assigns 被提取到单独的 gem 的原因。这一切都归结为测试您的代码做了什么 - 而不是它是如何做的。

参见: