Ruby on Rails:在Selenium测试中覆盖实例变量

时间:2017-10-04 17:41:58

标签: ruby-on-rails api selenium testing rspec

我的控制器中有一个操作,它使用我无法控制的API中的对象实例加载实例变量:

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

MyObj.find进行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 %>即可查看其中包含的内容。正如您所看到的,从我的spec文件和mymethod操作

调用时,index的返回值会有所不同

1 个答案:

答案 0 :(得分: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的实际实现,而是调用返回通过and_return指定的对象的rspec代码。 with方法仅用于缩小模拟范围,以便模拟在参数不匹配时不响应。在您的情况下,它可能是可选的。

请注意,我已将before(:all)更改为before(:each)。前者在整个套件之前只执行一次。由于您需要进行独立测试,因此您不希望有一个更改obj,这将会溢出到下一个测试。此外,似乎无法访问let块中的before(:all)

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

如果您无法访问外部API,那么提供canned responses可能会让您感到恼火,但至少存在明确的图层。