2017-10-04 66 views
0

我有我的控制器,从一个API我无法控制加载了一个对象的实例的实例变量的作用:Ruby on Rails的:硒覆盖实例变量测试

def index 
    @obj = MyObj.find(id: params[:id]) 
end 

MyObj中。找到一个API调用并返回该API返回的内容。

现在说我想为我的视图编写一个测试,但我无法使用测试数据库,因为我的应用程序依赖于该API。我永远无法指望API返回一个可测试对象,我想尝试的一些测试依赖于该对象的状态。

我希望能够在呈现我的视图之前,手动创建我自己的测试@obj,并让我的测试对该视图呈现工作在@obj通知的视图渲染上。

理想情况下是这样的:

before(:all) do 
    @obj = {attr1: "abc", attr2: 123} 
    driver.navigate.to("#{ENV['RAILS_HOST']}/my_view/123") 
end 

其中明确不起作用。有没有办法做到这一点?

编辑:试图存根方法似乎没有工作,这里是它目前的样子:

规格:

before(:each) do 
    allow(Library::Equipment) 
    .to receive(:mymethod) 
    .with(123) 
    .and_return("Stub method") 

    puts Library::Equipment.mymethod(123) 
    #prints "Stub method" 
    driver.navigate.to("#{ENV['RAILS_HOST']}/library/equipments/123/variables") 
end 

/library/equipments/:equipment_id/variables路线library/variables#index,它看起来像这样:

def index 
    @test = Library::Equipment.mymethod(123) 
    puts @test 
    #prints "Real method" 
    # other code... 
end 

我的Library::Equipment班有这样的班级方法:

def self.mymethod(param) 
    "Real method" 
end 

而在我的index.html.erb中,我只需要<%= @test %>即可查看它包含的内容。正如你所看到的,mymethod回报有所不同,当从我的规范文件,并从我的index行动称为

+0

使用'RSpec :: Mocks.with_temporary_scope'将允许您在'before(all)'中使用存根,但当范围结束时将删除存根。请删除'with_temporary_scope',并在同一时间之前将(:all)'前面的(:each)'/'前面的''改成''。 – ulferts

+0

结果是一样的,我编辑了问题以反映所做的更改。 – bpromas

回答

1

您可以通过rspec's allow方法存根调用MyObj.find

let(:obj) { { attr1: "abc", attr2: 123 } } 
let(:obj_id) { 123 } 

before(:each) do 
    allow(MyObj) 
    .to receive(:find) 
    .with(id: obj_id) 
    .and_return(obj) 

    driver.navigate.to("#{ENV['RAILS_HOST']}/my_view/123") 
end 

allow会为您提供的可能性,模拟对方法调用的响应(例如find)并返回您选择的答案。这样,当你的控制器打电话给MyObj.find时,find的实际实现不被调用,而是rspec代码,它返回通过and_return指定的对象。 with方法仅用于缩小模拟范围,以便模拟参数不匹配时不会响应。你的情况可能是可选的。

请注意,我将before(:all)更改为before(:each)。前者只会在整个套件之前执行一次。由于您需要进行独立测试,因此您不希望改变obj,这会影响下一次测试。此外,看起来不可能在before(:all)区块中访问let

鉴于硒测试通常是验收测试,但是我会发现这样的嘲讽可疑。

如果您无法访问外部API,则提供canned responses可能会令人恼怒,但至少需要清除被残留的图层。

+0

我无法让它工作。我收到了有关“在'before(:context)'钩子”中访问let声明obj_id的错误。另外,这个“允许”方法究竟是如何工作的?这是否意味着我每次调用MyObj.find(id:123)时都会返回该特定对象?这在我的控制器内工作? – bpromas

+1

@bpromas我阐述了回答你的问题的答案。 – ulferts

+0

这不起作用。在我的控制器动作中运行的'find'(由于我的'driver.navigate.to'调用)运行正常,未能找到id = 123的东西。但是,如果我调用MyObj.find(id:123)在'allow'方法下,它返回给我'{attr1:“abc”,attr2:123}',它应该是这样。两个问题:1)MyObj在这里意味着一个类,对吗? 2)在我的情况下,MyObj没有'find'方法,但包含支持模型中的一个。这是否改变了事情? – bpromas