【问题标题】:How to keep rspec tests DRY with lots of "have_link"如何使用大量“have_link”使 rspec 测试保持干燥
【发布时间】:2012-08-11 19:20:00
【问题描述】:

我是 Ruby on Rails 的新手,我现在正在使用 http://ruby.railstutorial.org

据我了解,该语言应该严格遵循这个 DRY 标准,但是在本教程中的测试驱动开发方面它是如此的湿。

例如

it { should have_link('Users', href: users_path) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }

这里有很多看起来几乎相同的行。

我试过了

it "should have following links from this array" do
    [
        ['Users', href: users_path],
        ['Profile', href: user_path(user)],
        ['Settings', href: edit_user_path(user)],
        ['Sign out', href: signout_path]
    ].each { |a| page.should have_link(a[0], a[1]) }
end

此代码有效,但看起来很难看,而且行数更多。

所以我想知道将数组添加到 have_link 方法是否是一种更好的方法。


我现在有了一个好主意,但我不知道如何实现它。

这是我的助手(它看起来不像我创建这个问题时所做的那样。它是在 Michaël Witrant 的回答后编辑的)

RSpec::Matchers.define :have_these_links do |*links|
    match do |actual|
        links.each do |link|
            have_link(link.first, link.extract_options!).matches?(actual)
        end
    end
end

现在这应该是我的测试

it { should have_these_links(['Users', href: users_path],
                        ['Profile', href: user_path(user)],
                        ['Settings', href: edit_user_path(user)],
                        ['Sign out', href: signout_path]) }

所以这可行,但它对用户不友好。当我运行测试并且页面上不存在链接时,它告诉我我没有这些链接。但是我可以让助手告诉我我缺少哪个链接。 这是我的错误代码

   expected #<Capybara::Session> to have these links ["Users", {:href=>"/users"}], ["Test Link", {:href=>"/Does_not_exist"}], and ["Profile", {:href=>"/users/991"}]
 # ./spec/requests/authentication_pages_spec.rb:42:in `block (4 levels) in <top (required)>'

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 rspec tdd railstutorial.org


    【解决方案1】:

    您可以编写自定义匹配器,但我认为这不是测试和 DRY 的想法。

    在代码中,DRY 的口头禅鼓励将软件的每一条知识都保存在一个独特且明确的位置。 这不是规范的目标。规范的目标是以明确且易于阅读的方式证明软件的正确性。

    重复

    it { should have_link('Users', href: users_path) }
    

    如果比声明和 [text, url] 数组并迭代它们更具可读性和易读性,即使在某种自定义匹配器中也是如此。

    在测试中,您应该更喜欢可读性而不是简洁性。

    【讨论】:

    • 即使这不是正确的做事方式,我认为这也是一种很好的学习方式。我是 Rails 和 ruby​​ 的新手,玩类和扩展它们对我来说是一种更了解它们的方式。但我牢记您的选择。
    • 在这种情况下,Michaël Witrant 给你的答案似乎是最好的方法。编写自定义匹配器是 Rspec 的最佳功能之一。
    【解决方案2】:

    要定义自定义匹配器,您可以阅读this feature 和一些inspiration

    然后写下类似的东西:

    RSpec::Matchers.define :have_links do |expected|
      match do |actual|
        expected.all? do |name, options|
          have_link(name, options).matches?(actual)
        end
      end
    end
    

    但是 IMO,您的第一次尝试是最好的编写方式:干净且易于阅读。

    【讨论】:

    • 感谢您的帮助!在您回答后,我已经编辑了我的问题。这适用于一些小的编辑,但我仍然不是我会去的地方(看我编辑的问题)。
    • 题外话:如果可以的话,请给我指出正确的方向,我可以在哪里找到有关“做|名称,选项|”的更多信息,我不明白我在哪里m 能够在 foreach 函数上使用乘法变量。 (我真的不知道用谷歌搜索什么,所以只要一个提示就可以了)
    • 您应该自定义失败消息。请参阅the doc 中的“自定义匹配器”。
    • 我不确定在哪里可以找到这些信息。它是关于 ruby​​ 在使用数组调用时如何处理块参数的。或者当yield 被调用时。也许这些关键字会对您有所帮助。当您使用数组作为唯一参数调用块时,并且该块接受多个参数时,数组会被展开。当您在数组数组上调用 each 时,您的块会发生这种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2017-01-28
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 2019-09-04
    • 1970-01-01
    相关资源
    最近更新 更多