【问题标题】:rspec it block inside looprspec 它在循环内阻塞
【发布时间】:2018-02-04 20:39:32
【问题描述】:

我想测试页面上的每个链接是否返回特定的状态代码。我有一个工作测试,如下所示:

it "does not throw 400/500 error for any link" do
  visit '/'
  within(".wrapper") do
    all('a').each do |link|
      http_status = Faraday.head(link[:href].to_s).status
      puts "#{link.text}, #{http_status}"
      expect((400..500)).not_to include(http_status) 
    end
  end

但是,这对于输出来说非常糟糕,因为所有链接都在一个测试中检查(因此测试中的 puts 会告诉我哪个链接破坏了测试)。我希望能够对每个链接进行单独的测试,而无需为页面上的每个链接手动编写测试。

我试过了:

context "does not throw 400/500 error for any link" do
  visit '/'
  within(".wrapper") do
    all('a').each do |link|
      it "does not throw 400/500 error for #{link}" do
        link_status_code_is_not(link, (400..500))
      end
    end
  end
end

得到了这个错误

`visit` is not available on an example group (e.g. a `describe` or
`context` block). It is only available from within individual examples 
(e.g. `it` blocks) or from constructs that run in the scope of an 
example (e.g. `before`, `let`, etc).

所以我尝试将访问移至 before 钩子,但遇到了与 inside 块相同的问题(我无法真正移动)。我已经能够在茉莉花中做这样的事情,但我似乎无法在 rspec 中找到一种方法。

tl:博士;有什么办法可以将 it 块放在 rspec 的循环中?

【问题讨论】:

  • This 可能会对您有所帮助。如果您使用描述块而不是上下文块,似乎可以做到这一点。
  • 我一直这样做。为什么你不能在it 块中使用visit
  • @SteveTurczyn 我可以在 it 块内进行访问,但这不是问题。我正在尝试将除 http 状态检查之外的所有内容移到 it 块之外,以便页面上的每个链接都有一个新的 it 块。
  • 有多少链接?与其这样做,不如直接制作一个链接名称为string 的数组,这样会更有用。
  • @Rhunal 我将如何收集这些链接?我不能在 it 块之外使用访问或使用功能。我可以尝试直接使用 selenium 从页面读取数据,然后对其进行测试,但这似乎是错误的做法。我很惊讶在 rspec 中没有一种简单的方法可以做到这一点。我可以很容易地用茉莉花做类似的事情。

标签: ruby rspec


【解决方案1】:

您可以在循环内创建it 块:

RSpec.describe "numbers" do
  [*1..10].each do |number|
    it "#{number} should not be multiple of 10" do
      expect(number % 10).not_to be_zero
    end
  end
end

不过,您的问题是,您似乎无法在 it 块(或“在示例范围内运行的构造”)之外使用 visit,并且您需要从以下页面中获取数据你 visit 并循环并从该数据创建 it 块。我不确定这是否可以很好地完成。

如果您想要的只是更好的链接输出,您可以使用aggregate_failuresCustomized messages 为您的测试提供更好的输出。举一个人为的例子,假设我有很多动态,只能在 it 块内或在示例范围内运行的构造中可用,成对的数字,我需要确保它们的乘积都不是 10 的倍数:

RSpec.describe "numbers" do
  it "are not a multiple of 10" do
    [*1..10].product([*1..10]).each do |base, multiplier|
      expect((base * multiplier) % 10).not_to be_zero
    end
  end
end

这里的输出不是很好,它只是告诉我期望 0.zero? 返回 false,得到了 true,而不是哪对数字失败了。不过,通过使用聚合失败和自定义消息,我可以解决这个问题:

RSpec.describe "numbers" do
  it "are not a multiple of 10" do
    aggregate_failures do
      [*1..10].product([*1..10]).each do |base, multiplier|
        expect((base * multiplier) % 10).not_to be_zero, "#{base} * #{multiplier} is a multiple of 10"
      end
    end
  end
end

现在,我在统计信息中只报告了 1 次失败(这对您的用例可能是好是坏),但我收到了 27 次子失败:

Failures:

  1) numbers are not a multiple of 10
     Got 27 failures from failure aggregation block.

     1.1) Failure/Error: ...
            1 * 10 is a multiple of 10
          # ...backtrace...
     1.2) Failure/Error: ...
            2 * 5 is a multiple of 10
          # ...backtrace...
     ...
     1.27) Failure/Error: ...
             10 * 10 is a multiple of 10

【讨论】:

  • 这很接近,但问题是我看不到测试的进度。页面上有大量链接,所以这个测试大约需要 30 秒才能完成。我真的很想将每个链接的检查打破到它自己的测试中。我可以通过从描述块内的循环中调用包含 it 块的函数来使用 jasmine 轻松完成此操作,但这似乎在 rspec 中是不允许的。不过感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-27
  • 2012-11-01
  • 1970-01-01
  • 2018-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多