【问题标题】:Mocking download link / checking link generation against controller methods with Capybara使用 Capybara 针对控制器方法模拟下载链接/检查链接生成
【发布时间】:2018-05-23 23:42:51
【问题描述】:

在某个页面的 Capybara 功能规范中,我有一个下载链接:

download_link = find_link(expected_link_text)

我想检查生成的链接是否是下载文件的正确链接,即它将使用正确的模型对象在我的 FileController 上调用 download()

RSpec-Rails 似乎有很多方法可以得到我想要的。例如,在controller spec 中,我可以在控制器上使用普通的 RSpec 断言:

expect(controller).to receive(:download).with(expected_id)
# download_link = find_link(expected_link_text) # can't do this in a controller spec
# visit(download_link)                          # can't do this in a controller spec

在路由规范中,我可以使用 route_to():

# download_link = find_link(expected_link_text)       # can't do this in a routing spec
expect(get: download_link[href]).to route_to(controller: 'file', action: 'download', id: expected_id)

但在功能规范中,controllerroute_to() 均不可用。

通过以下恶作剧和在调试器中的大量探索,我能够将route_to() 包含在我的测试中:

describe 'the page' do
  it 'should let the user download a file' do
    self.class.send(:include, RSpec::Rails::Matchers::RoutingMatchers)       # hack to get routing matchers into feature test
    self.class.send(:include, ActionDispatch::Assertions::RoutingAssertions) # RoutingMatchers uses this internally
    self.class.send(:define_method, :message) { |msg, _| msg }               # RoutingAssertions expects message() to be included from somewhere
    @routes = Rails.application.routes                                       # RoutingAssertions needs @routes

    download_link = find_link(expected_link_text)
    expect(get: download_link[href]).to route_to(controller: 'file', action: 'download', id: expected_id) # works!
  end
end

这确实有效,但它是香蕉。是否有任何开箱即用的方法可以将 Capybara 混合到其他类型的规格中,或者将其他类型的规格混合到功能规格中?或者只是一种更清洁的 Rails-y(可能是非 RSpec)方式来获取路线?


注意:路由没有命名,所以我不能使用 URL 助手(我不认为);由于历史原因,URL 路径本身是不连贯的噪音,所以我不只是想以字符串形式断言 href。

【问题讨论】:

    标签: capybara rspec-rails


    【解决方案1】:

    正如你所说,如果你想检查一个特定的控制器方法被调用,这将是一个控制器规范,如果你想验证路由,它将是一个路由规范。使用 Capybara,您应该编写功能规范/系统测试——这意味着没有模拟/存根,而是运行端到端测试。配置您用于下载文件的任何驱动程序,然后单击链接,下载文件,并验证是否下载了正确的文件。另一种选择是只使用url_for,而不是尝试包含所有额外的东西,然后就这样做

    expect(download_link[href]).to eq url_for(controller: 'file', action: 'download', id: expected_id)
    

    或者更好

    expect(page).to have_link(expected_link_text, href: url_for(controller: 'file', action: 'download', id: expected_id))
    

    但如果你正在测试文件下载,你真的应该只下载文件。

    如果您必须处理编码问题,您可以使用过滤器块重写期望并解析路径/网址以进行规范化

    expect(page).to have_link(expected_link_text) do |link|
      Addressable::URI.parse(link[:href]) == Addressable::URI.parse(url_for(controller: 'file', action: 'download', id: expected_id))
    end
    

    【讨论】:

    • 没有文件。这是整个微服务星座的前端。 url_for 可能是正确的答案,尽管存在一些 URL 编码问题。
    • (奇怪的是,route_to 对编码问题是透明的。)
    • @DavidMoles 您可以控制测试期间使用的数据,因此应该可以避免编码问题,但是如果您不得不遇到它们,您可以执行我添加到答案中的操作。
    • 这是一个遗留系统,我正在编写回归测试以确保在更新库时没有任何问题,因此,遗憾的是,如果生成链接的代码坚持对其中的部分进行双重编码,测试需要支持这一点。不过,URI.parse() 的技巧值得记住。
    猜你喜欢
    • 2017-10-29
    • 2012-08-05
    • 2019-08-07
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    • 1970-01-01
    相关资源
    最近更新 更多