组合匹配器

RSpec 的匹配器旨在可组合,以便您可以将它们组合在一起以表达您所期望的确切细节,但不多不少。这可以通过使用匹配器代替精确值来指定您期望的必要方面,来帮助您避免编写过度指定且脆弱的规范。

以下匹配器接受匹配器作为参数

* `change { }.by(matcher)`
* `change { }.from(matcher).to(matcher)`
* `contain_exactly(matcher, matcher, matcher)`
* `end_with(matcher, matcher)`
* `include(matcher, matcher)`
* `include(:key => matcher, :other => matcher)`
* `match(arbitrary_nested_structure_with_matchers)`
* `output(matcher).to_stdout`
* `output(matcher).to_stderr`
* `raise_error(ErrorClass, matcher)`
* `start_with(matcher, matcher)`
* `throw_symbol(:sym, matcher)`
* `yield_with_args(matcher, matcher)`
* `yield_successive_args(matcher, matcher)`

请注意,许多内置匹配器不接受匹配器参数,因为它们具有不允许使用匹配器参数的精确语义。例如,equal(some_object) 旨在仅当实际参数和预期参数是对同一对象的引用时才通过。在这里支持匹配器参数没有意义。

所有 RSpec 的内置匹配器都具有一个或多个别名,这些别名允许您使用名词短语而不是动词形式,因为它们在作为组合参数时读起来更好。它们还提供自定义的失败输出,以便失败消息也读起来更好。

这里没有列出所有这些别名,但下面列出了一些用于以下示例的别名

* `be < 2` => `a_value < 2`
* `be > 2` => `a_value > 2`
* `be_an_instance_of` => `an_instance_of`
* `be_within` => `a_value_within`
* `contain_exactly` => `a_collection_containing_exactly`
* `end_with` => `a_string_ending_with`, `ending_with`
* `match` => `a_string_matching`
* `start_with` => `a_string_starting_with`

有关完整列表,请参阅 RSpec::Matchers 模块的 API 文档。

使用 change 组合匹配器

给定一个名为“change_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `change`" do
  specify "you can pass a matcher to `by`" do
    k = 0
    expect { k += 1.05 }.to change { k }.
      by( a_value_within(0.1).of(1.0) )
  end

  specify "you can pass matchers to `from` and `to`" do
    s = "food"
    expect { s = "barn" }.to change { s }.
      from( a_string_matching(/foo/) ).
      to( a_string_matching(/bar/) )
  end
end

我运行 rspec change_spec.rb

那么这些示例应该全部通过。

使用 contain_exactly 组合匹配器

给定一个名为“contain_exactly_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `contain_exactly`" do
  specify "you can pass matchers in place of exact values" do
    expect(["barn", 2.45]).to contain_exactly(
      a_value_within(0.1).of(2.5),
      a_string_starting_with("bar")
    )
  end
end

我运行 rspec contain_exactly_spec.rb

那么这些示例应该全部通过。

使用 end_with 组合匹配器

给定一个名为“end_with_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `end_with`" do
  specify "you can pass matchers in place of exact values" do
    expect(["barn", "food", 2.45]).to end_with(
      a_string_matching("foo"),
      a_value > 2
    )
  end
end

我运行 rspec end_with_spec.rb

那么这些示例应该全部通过。

使用 include 组合匹配器

给定一个名为“include_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `include`" do
  specify "you can use matchers in place of array values" do
    expect(["barn", 2.45]).to include( a_string_starting_with("bar") )
  end

  specify "you can use matchers in place of hash values" do
    expect(:a => "food", :b => "good").to include(:a => a_string_matching(/foo/))
  end

  specify "you can use matchers in place of hash keys" do
    expect("food" => "is good").to include( a_string_matching(/foo/) )
  end
end

我运行 rspec include_spec.rb

那么这些示例应该全部通过。

使用 match 组合匹配器

给定一个名为“match_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `match`" do
  specify "you can match nested data structures against matchers" do
    hash = {
      :a => {
        :b => ["foo", 5.0],
        :c => { :d => 2.05 }
      }
    }

    expect(hash).to match(
      :a => {
        :b => a_collection_containing_exactly(
          a_string_starting_with("f"),
          an_instance_of(Float)
        ),
        :c => { :d => (a_value < 3) }
      }
    )
  end
end

我运行 rspec match_spec.rb

那么这些示例应该全部通过。

使用 output 组合匹配器

给定一个名为“output_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `output`" do
  specify "you can pass a matcher in place of the output (to_stdout)" do
    expect {
      print 'foo'
    }.to output(a_string_starting_with('f')).to_stdout
  end
  specify "you can pass a matcher in place of the output (to_stderr)" do
    expect {
      warn 'foo'
    }.to output(a_string_starting_with('f')).to_stderr
  end
end

我运行 rspec output_spec.rb

那么这些示例应该全部通过。

使用 raise_error 组合匹配器

给定一个名为“raise_error_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `raise_error`" do
  specify "you can pass a matcher in place of the message" do
    expect {
      raise RuntimeError, "this goes boom"
    }.to raise_error(RuntimeError, a_string_ending_with("boom"))
  end
end

我运行 rspec raise_error_spec.rb

那么这些示例应该全部通过。

使用 start_with 组合匹配器

给定一个名为“start_with_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `start_with`" do
  specify "you can pass matchers in place of exact values" do
    expect(["barn", "food", 2.45]).to start_with(
      a_string_matching("bar"),
      a_string_matching("foo")
    )
  end
end

我运行 rspec start_with_spec.rb

那么这些示例应该全部通过。

使用 throw_symbol 组合匹配器

给定一个名为“throw_symbol_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `throw_symbol`" do
  specify "you can pass a matcher in place of a throw arg" do
    expect {
      throw :pi, Math::PI
    }.to throw_symbol(:pi, a_value_within(0.01).of(3.14))
  end
end

我运行 rspec throw_symbol_spec.rb

那么这些示例应该全部通过。

使用 yield_with_args 组合匹配器

给定一个名为“yield_with_args_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `yield_with_args`" do
  specify "you can pass matchers in place of the args" do
    expect { |probe|
      "food".tap(&probe)
    }.to yield_with_args(a_string_matching(/foo/))
  end
end

我运行 rspec yield_with_args_spec.rb

那么这些示例应该全部通过。

使用 yield_successive_args 组合匹配器

给定一个名为“yield_successive_args_spec.rb”的文件,其中包含

RSpec.describe "Passing matchers to `yield_successive_args`" do
  specify "you can pass matchers in place of the args" do
    expect { |probe|
      [1, 2, 3].each(&probe)
    }.to yield_successive_args(a_value < 2, 2, a_value > 2)
  end
end

我运行 rspec yield_successive_args_spec.rb

那么这些示例应该全部通过。

使用复合 and 表达式组合匹配器

给定一个名为“include_spec.rb”的文件,其中包含

RSpec.describe "Passing a compound matcher expression to `include`" do
  example do
    expect(["food", "drink"]).to include( a_string_starting_with("f").and ending_with("d"))
  end
end

我运行 rspec include_spec.rb

那么这些示例应该全部通过。