我正在使用Ruby on Rails 3.1.0和rspec-rails 2 gem。我正在测试我的控制器代码(BTW:我是rspec的新手),我想让类对象实例返回预定义的值。也就是说,在我的控制器中我有:
def create
...
if @current_user.has_authorization?
...
else
...
end
end
为了测试else
语句的“if
部分”,我想使其成为可能(对于我正在处理的当前规范示例 - 请参阅下面的示例实现) @current_user.has_authorization?
会返回false
。
我该怎么做?
我在我的spec文件中尝试了以下内容,但似乎无法正常工作:
it "should have no authorization" do
@current_user.stub(:has_authorization?).and_return(false)
# I also tried the following and it still doesn't work
# @current_user.should_receive(:has_authorization?).and_return(false)
post :create
...
end
答案 0 :(得分:1)
@current_user
与控制器上下文中的@current_user
不同。一个是实例变量,在Rails运行的控制器类的实例中。另一个是rspec测试中的实例变量。
你不应该捅你的用户变量,而是需要这样做,以便Rails找到测试框架提供的用户。看看this example。
答案 1 :(得分:0)
要避免此问题,您可以使用mocha,为此,请执行以下操作:
将mocha gem添加到Gemfile
并运行bundle install
。
然后更改spec_helper.rb
文件
RSpec.configure do |config|
config.mock_with :mocha
# config.mock_with :rspec
end
然后在您的规范中,您可以执行此操作
it "should have no authorization" do
User.any_instance.stubs(:has_authorization?).returns(false)
post :create
...
end
此(或the correct answer from Coderer)将解决您的问题。
请注意,据我所知,Rspec模拟函数中没有any_instance
等效项。
答案 2 :(得分:0)
当您的规范正在运行时,self
指向一个测试对象(在某个时间内在规范中尝试p self
或puts self.class
并自行查看),因此@current_user
是引用该测试对象上的实例变量。它与控制器上的@current_user
实例变量没有任何关系。
执行所需操作的一种方法是在控制器上创建current_user 方法或访问者,然后调用它而不是直接访问@current_user
。然后,您可以从规范中存根或模拟该方法,假设您可以获得指向控制器实例的指针。
另一种方法是直接从规范中设置@current_user
变量。再次,获取指向您的控制器实例的指针,然后执行x = mock("user"); controller.instance_variable_set(:@current_user, x)
,然后您可以在x
上模拟/存根方法。