期望断言仅对数组中的一个元素为真

Expect assertion that is only true for one element in an array

我想断言数组至少包含一个符合 RSpec 期望的元素。但是数组中的大部分元素都不会通过预期。所以我想做这样的事情:

it "finds one element that matches" do
  array.any? do |element|
    expect(element).to eq("expected value")
  end
end

如果任何元素符合预期,则测试通过。但是,当然,正如我在这里写的那样,测试会失败。

RSpec 中是否有一个模式可以完成我想要完成的事情?


我不想这样做:

it "finds one element that matches" do
  expect(array.any? {|val| val == "expected value"}).to be_true
end

因为我不清楚如何手动检查与我在测试中需要使用的匹配器相同的东西。我想使用 have_attributes 匹配器,它做了一些 subtle metaprogramming magic 我不想冒险尝试自己重新实现。

您可以使用 include 匹配器来 compose matchers:

expect(array).to include(a_string_matching(/foo/))

尽管语法有些笨拙,但您可以将其与 have_attributes:

一起使用
expect(obj).to have_attributes(tags: include(a_string_matching(/foo/))

但是如果出于某种原因这不够灵活,您可以使用 satisfy 匹配器:

expect(array).to satisfy {|arr| arr.any? {|val| val == "expected value"})

double-nested 块本身有点笨拙,但是 satisfy 的灵活性让你可以用它做各种事情,你可以使用 include 匹配器来实现。例如:

require "rspec"
require "ostruct"

obj = OpenStruct.new(name: "foobar", tags: %w(bin bazzle))

describe obj do
  it "has a bin tag" do
    is_expected.to have_attributes(tags: include(/bin/))
  end

  it "has a tag 3 characters long" do
    is_expected.to have_attributes(tags: include(satisfy { |t| t.length == 3 }))
  end
end

如果您愿意添加一个 gem,我真的很喜欢 rspec-its 像这样的情况:他们可以清理不保证他们的对象的个别属性的规范很好地拥有自己的主题块:

describe obj do
  its(:tags) { is_expected.to be_a Array }
  its(:tags) { is_expected.to include "bin" }
end

RSpec 有 composing matchers 可以与 expect(array).to include 一起使用来实现我想要的。例如:

expect(array).to include(a_string_matching("expected value"))

对于 have_attributes 匹配器,RSpec 有一个名为 an_object_having_attributes 的别名,允许我写:

expect(array).to include(an_object_matching(object_i_want_duplicated))