从帮助器规范内部对辅助方法进行存根

Gab*_*lli 6 ruby rspec ruby-on-rails rspec-rails

我正在构建一个Rails应用程序并使用RSpec制定测试.

我为我正在创建的方法编写测试current_link_to.该方法应该检查当前页面是否对应于我传递它的路径,并将current该类添加到生成的链接中以防万一.

这是规格:

require "spec_helper"

describe ApplicationHelper do
  describe "#current_link_to" do
    let(:name)     { "Products" }
    let(:path)     { products_path }
    let(:rendered) { current_link_to(name, path) }

    context "when the given path is the current path" do
      before { visit(path) }

      it "should return a link with the current class" do
        # Uses the gem "rspec-html-matchers" (https://github.com/kucaahbe/rspec-html-matchers)
        expect(rendered).to have_tag("a", with: { href: path, class: "current" }) do
          with_text(name)
        end
      end
    end

    context "when the given path is not the current path" do
      before { visit(about_path) }

      it "should return a link without the current class" do
        expect(rendered).to have_tag("a", with: { href: path }, without: { class: "current" } ) do
          with_text(name)
        end
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后我按照规范尝试实现我的方法:

module ApplicationHelper
  def current_link_to(name, path, options={})
    options.merge!({ class: "#{options[:class]} current".strip }) if current_page?(path)

    link_to(name, path, options)
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,测试失败并出现以下错误:

Failure/Error: let(:rendered) { current_link_to(name, path) }

RuntimeError: You cannot use helpers that need to determine the current page unless your view context provides a Request object in a #request method
Run Code Online (Sandbox Code Playgroud)

因为我不需要current_page? 帮助方法来对请求执行检查,所以我认为将它存根是有意义的.

我尝试了以下方法,但没有一个工作:

  1. helper.double(:current_page? => true)
    似乎存根该helper.current_page? 方法,但它与我的函数调用的方法不同.
  2. allow(ActionView::Helpers::UrlHelper).to receive(:current_page?).and_return(true)
    存根似乎根本没有效果

在写这个问题时,我偶然发现了解决方案.我设法current_page?在一个before块中使用它来存根方法:

allow(self).to receive(:current_page?).and_return(true)
Run Code Online (Sandbox Code Playgroud)

它有效,但是这个解决方案提出的问题比它真正回答的要多.我现在对这是如何工作感到困惑,因为self在一个before块中响应current_page?并且所述方法实际上与我的助手调用的方法完全相同似乎很奇怪.

即使在阅读文档并试图通过puts调用我的代码来弄清楚它是如何工作之后,以下疑惑仍然困扰着我:

  • 为什么在规范中可以直接使用辅助方法,当RSpec文档提到它们应该作为helper所有辅助规范中可用对象的方法可用时?
  • 如何在RSpec 块中存根current_page?方法以某种方式反映到我的助手调用的实际方法?是否在帮助我由于某种原因,引用同你可以在找块?RSpec或Rails是否包括和混合物?selfbeforeselfselfbefore
  • 如果同样self包含我的规范和我的助手,self在这种情况下究竟是指什么,为什么它到处都是一样的?

如果有人可以帮我解决这个问题会很好,因为这让我大吃一惊,而且我害怕使用我不太了解的代码.

Ter*_*ryS 1

恕我直言,您在这里测试的功能有点太多了。诀窍是仅测试您需要测试的位。

在这种情况下,您只需测试当前类是否在需要时添加,而在不需要时不添加。

这段代码应该可以帮助你:

require 'rails_helper'

# Specs in this file have access to a helper object that includes
# the ApplicationHelper. 
RSpec.describe ApplicationHelper, type: :helper do

  describe 'current_link_to' do
    let(:subject) { helper.current_link_to('some_name', 'some_path', options = {}) }

    context 'where the path is current' do
      before do
        allow(helper).to receive(:current_page?).and_return true
      end
      it 'should include the current class' do
        expect(subject).to match /current/
      end
    end

    context 'where the path is not current' do
      before do
        allow(helper).to receive(:current_page?).and_return false
      end
      it 'should not include the current class' do
        expect(subject).to_not match /current/
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我有点油嘴滑舌,只测试了返回字符串中是否存在“current”。如果您想更精确,您可以测试类似“class =“current””的内容。

另一个关键是页面顶部的注释,Rails 会将其插入到空白帮助器规范中:

# Specs in this file have access to a helper object that includes
# the ApplicationHelper. 
Run Code Online (Sandbox Code Playgroud)

这意味着您可以在上面的评论中使用“self”时使用“helper”,这使事情变得更清晰(恕我直言)

希望能帮助到你!