模块:RSpec::Matchers

扩展自
DSL
包含于
DSL::Matcher
定义在
lib/rspec/matchers.rb,
lib/rspec/matchers/dsl.rb,
lib/rspec/matchers/built_in.rb,
lib/rspec/matchers/composable.rb,
lib/rspec/matchers/built_in/be.rb,
lib/rspec/matchers/built_in/eq.rb,
lib/rspec/matchers/built_in/all.rb,
lib/rspec/matchers/built_in/eql.rb,
lib/rspec/matchers/built_in/has.rb,
lib/rspec/matchers/fail_matchers.rb,
lib/rspec/matchers/built_in/cover.rb,
lib/rspec/matchers/built_in/equal.rb,
lib/rspec/matchers/built_in/exist.rb,
lib/rspec/matchers/built_in/match.rb,
lib/rspec/matchers/built_in/yield.rb,
lib/rspec/matchers/aliased_matcher.rb,
lib/rspec/matchers/built_in/change.rb,
lib/rspec/matchers/built_in/output.rb,
lib/rspec/matchers/built_in/include.rb,
lib/rspec/matchers/built_in/satisfy.rb,
lib/rspec/matchers/english_phrasing.rb,
lib/rspec/matchers/matcher_protocol.rb,
lib/rspec/matchers/built_in/compound.rb,
lib/rspec/matchers/matcher_delegator.rb,
lib/rspec/matchers/built_in/be_within.rb,
lib/rspec/matchers/built_in/operators.rb,
lib/rspec/matchers/multi_matcher_diff.rb,
lib/rspec/matchers/built_in/be_between.rb,
lib/rspec/matchers/built_in/be_kind_of.rb,
lib/rspec/matchers/built_in/respond_to.rb,
lib/rspec/matchers/built_in/raise_error.rb,
lib/rspec/matchers/built_in/base_matcher.rb,
lib/rspec/matchers/built_in/throw_symbol.rb,
lib/rspec/matchers/generated_descriptions.rb,
lib/rspec/matchers/built_in/be_instance_of.rb,
lib/rspec/matchers/built_in/contain_exactly.rb,
lib/rspec/matchers/built_in/have_attributes.rb,
lib/rspec/matchers/built_in/count_expectation.rb,
lib/rspec/matchers/built_in/start_or_end_with.rb

概述

RSpec::Matchers 提供了许多有用的匹配器,我们用它们来定义预期。任何实现了 匹配器协议 的对象都可以用作匹配器。

谓词

除了明确定义的匹配器外,RSpec 还会为任何任意谓词动态创建自定义匹配器,使您的规范更自然。

Ruby 谓词是一个以“?”结尾并返回 true 或 false 的方法。常见的例子是 empty?nil?instance_of?

您只需编写 expect(..).to be_ 后面跟着没有问号的谓词,RSpec 就会从那里弄清楚。例如

expect([]).to be_empty     # => [].empty?() | passes
expect([]).not_to be_empty # => [].empty?() | fails

除了在谓词匹配器前加上 "be_",您还可以使用 "be_a_" 和 "be_an_",使您的规范更自然

expect("a string").to be_an_instance_of(String) # =>"a string".instance_of?(String) # passes

expect(3).to be_a_kind_of(Integer)          # => 3.kind_of?(Numeric)     | passes
expect(3).to be_a_kind_of(Numeric)          # => 3.kind_of?(Numeric)     | passes
expect(3).to be_an_instance_of(Integer)     # => 3.instance_of?(Integer) | passes
expect(3).not_to be_an_instance_of(Numeric) # => 3.instance_of?(Numeric) | fails

RSpec 还会为像 has_key? 这样的谓词创建自定义匹配器。要使用此功能,只需声明对象应该 have_key(:key),RSpec 就会在目标上调用 has_key?(:key)。例如

expect(:a => "A").to have_key(:a)
expect(:a => "A").to have_key(:b) # fails

您可以使用此功能调用以 "has_" 开头的任何谓词,无论是 Ruby 库中的(如 Hash#has_key?)还是您自己类中编写的。

请注意,RSpec 不会为这些动态谓词匹配器提供可组合的别名。不过,您可以轻松地定义自己的别名

RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin
expect(user_list).to include(a_user_who_is_an_admin)

别名匹配器

使用 Matchers.alias_matcher,您可以轻松地为给定匹配器创建一个替代名称。

描述也会根据新名称更改

RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to
sum_to(3).description # => "sum to 3"
a_list_that_sums_to(3).description # => "a list that sums to 3"

或者您可以指定一个像这样的自定义描述

RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description|
  description.sub("be sorted by", "a list sorted by")
end
be_sorted_by(:age).description # => "be sorted by age"
a_list_sorted_by(:age).description # => "a list sorted by age"

自定义匹配器

当您发现没有一个库存匹配器能提供自然的感觉预期时,您可以非常轻松地使用 RSpec 的匹配器 DSL 或从头开始编写自己的匹配器。

匹配器 DSL

想象一下,您正在编写一个游戏,其中玩家可以在虚拟棋盘上的不同区域。要指定 bob 应该在区域 4,您可以说

expect(bob.current_zone).to eql(Zone.new("4"))

但您可能会发现说

expect(bob).to be_in_zone("4")

和/或

expect(bob).not_to be_in_zone("3")

您可以像这样创建一个匹配器

RSpec::Matchers.define :be_in_zone do |zone|
  match do |player|
    player.in_zone?(zone)
  end
end

这将生成一个be_in_zone方法,该方法返回一个带有逻辑默认失败消息的匹配器。您可以覆盖失败消息和生成的描述,如下所示

RSpec::Matchers.define :be_in_zone do |zone|
  match do |player|
    player.in_zone?(zone)
  end
  failure_message do |player|
    # generate and return the appropriate string.
  end
  failure_message_when_negated do |player|
    # generate and return the appropriate string.
  end
  description do
    # generate and return the appropriate string.
  end
end

每个消息生成方法都可以访问传递给create方法的块参数(在本例中为zone)。失败消息方法(failure_messagefailure_message_when_negated)被传递实际值(接收者expect(..)expect(..).not_to).

从头开始的自定义匹配器

您也可以从头开始编写一个自定义匹配器,如下所示

class BeInZone
  def initialize(expected)
    @expected = expected
  end
  def matches?(target)
    @target = target
    @target.current_zone.eql?(Zone.new(@expected))
  end
  def failure_message
    "expected #{@target.inspect} to be in Zone #{@expected}"
  end
  def failure_message_when_negated
    "expected #{@target.inspect} not to be in Zone #{@expected}"
  end
end

... 和一个像这样的方法

def be_in_zone(expected)
  BeInZone.new(expected)
end

然后将方法暴露给您的规范。这通常通过将方法和类包含在模块中来完成,然后将模块包含在您的规范中

module CustomGameMatchers
  class BeInZone
    # ...
  end
  def be_in_zone(expected)
    # ...
  end
end
describe "Player behaviour" do
  include CustomGameMatchers
  # ...
end

或者您可以将它全局包含在 spec_helper.rb 文件中required 从您的规范文件(s)中

RSpec::configure do |config|
  config.include(CustomGameMatchers)
end

使自定义匹配器可组合

RSpec 的内置匹配器旨在进行组合,如以下表达式所示

expect(["barn", 2.45]).to contain_exactly(
  a_value_within(0.1).of(2.5),
  a_string_starting_with("bar")
)

自定义匹配器可以轻松地参与像这样的组合匹配器表达式。将 Composable 包含在您的自定义匹配器中,以使其支持进行组合(使用 DSL 定义的匹配器会自动包含此功能)。在匹配器的 matches? 方法(或使用 DSL 的 match 块)中,使用 values_match?(expected, actual) 而不是 expected == actual。在幕后,values_match? 能够匹配包含匹配器和非匹配器对象的任意嵌套数据结构。它使用 ===== 来执行匹配,如果其中任何一个返回 true,则认为值匹配。Composable 混合还提供一些辅助方法,用于在匹配器的描述或失败消息中显示匹配器描述。

RSpec 的内置匹配器都有许多别名,它们将匹配器从动词短语(如 be_within)改写为名词短语(如 a_value_within),这在匹配器作为参数传递给组合匹配器表达式时更易读,并且还在匹配器的 description 中使用名词短语措辞,以获得可读的失败消息。您可以使用 Matchers.alias_matcher 以类似的方式为您的自定义匹配器创建别名。

否定匹配器

有时,如果您想使用更具描述性的名称来测试相反情况,而不是使用 not_to,可以使用 Matchers.define_negated_matcher

RSpec::Matchers.define_negated_matcher :exclude, :include
include(1, 2).description # => "include 1 and 2"
exclude(1, 2).description # => "exclude 1 and 2"

虽然最明显的否定形式可能是添加 not_ 前缀,但使用该形式获得的失败消息可能会令人困惑(例如,“预期 [实际] 不 [动词],但没有”。我们发现为否定形式找到一个更积极的名称效果最好,例如 avoid_changing 而不是 not_change

在命名空间下定义

模块: BuiltIn, Composable, DSL, EnglishPhrasing, FailMatchers 类: AliasedMatcher, MatcherProtocol, MultiMatcherDiff

类方法摘要 折叠

实例方法摘要 折叠

DSL 中包含的方法

alias_matcher, define, define_negated_matcher

动态方法处理

此类通过method_missing方法

#method_missing(method, *args, &block) ⇒Object (私有)

961
962
963
964
965
966
967
968
969
970
# File 'lib/rspec/matchers.rb', line 961
def method_missing(method, *args, &block)
  case method.to_s
  when BE_PREDICATE_REGEX
    BuiltIn::BePredicate.new(method, *args, &block)
  when HAS_REGEX
    BuiltIn::Has.new(method, *args, &block)
  else
    super
  end
end

类方法详情

.alias_matcher(new_name, old_name, options = {}, &description_override) ⇒Object

250
251
252
# File 'lib/rspec/matchers.rb', line 250
def self.alias_matcher(*args, &block)
  super(*args, &block)
end

.clear_generated_descriptionObject

此方法是私有 API 的一部分。 应尽可能避免使用此方法,因为它可能会在将来被移除或更改。

由 rspec-core 在示例之后用于清除用于生成描述的状态。

11
12
13
14
# File 'lib/rspec/matchers/generated_descriptions.rb', line 11
def self.clear_generated_description
  self.last_matcher = nil
  self.last_expectation_handler = nil
end

.configurationRSpec::Expectations::Configuration

委托给 Expectations.configuration。这是因为 rspec-core 的 expect_with 选项在 mixin (RSpec::Matchers) 上查找 configuration 方法以向块生成。

返回值

951
952
953
# File 'lib/rspec/matchers.rb', line 951
def self.configuration
  Expectations.configuration
end

.define(name, &declarations) ⇒Object


    
# File 'lib/rspec/matchers.rb', line 257

.define_negated_matcher(negated_name, base_name, &description_override) ⇒Object


    
# File 'lib/rspec/matchers.rb', line 260

.generated_descriptionObject

此方法是私有 API 的一部分。 应尽可能避免使用此方法,因为它可能会在将来被移除或更改。

根据最后一个期望生成一个示例描述。由 rspec-core 的单行语法使用。

19
20
21
22
# File 'lib/rspec/matchers/generated_descriptions.rb', line 19
def self.generated_description
  return nil if last_expectation_handler.nil?
  "#{last_expectation_handler.verb} #{last_description}"
end

实例方法详情

#aggregate_failures(label = nil, metadata = {}) { ... } ⇒Object

注意

此功能的实现使用了一个线程局部变量,这意味着如果你在另一个线程中出现期望失败,它会像正常一样中止。

允许在提供的块中出现多个期望失败,然后将它们聚合到一个异常中,而不是像正常一样在第一个期望失败时中止。这使你能够看到来自整个期望集的所有失败,而无需将每个期望拆分成自己的示例(如果示例设置成本很高,这可能会降低速度)。

示例

aggregate_failures("verifying response") do
  expect(response.status).to eq(200)
  expect(response.headers).to include("Content-Type" => "text/plain")
  expect(response.body).to include("Success")
end

参数

  • label (String) (默认为: nil)

    此聚合块的标签,它将包含在聚合的异常消息中。

  • metadata (Hash) (默认为: {})

    关于此失败聚合块的附加元数据。如果多个期望失败,它将从 Expectations::MultipleExpectationsNotMetError 异常中暴露出来。主要用于内部 RSpec 使用,但你也可以使用它。

产量

  • 包含你想要的尽可能多的期望的块。该块只是被生成,所以你可以相信在块之外有效的任何内容在块中都应该有效。

引发

305
306
307
# File 'lib/rspec/matchers.rb', line 305
def aggregate_failures(label=nil, ={}, &block)
  Expectations::FailureAggregator.new(label, ).aggregate(&block)
end

#all(expected) ⇒Object

注意

不支持否定形式 not_to all。可以使用 not_to include 或将匹配器的否定形式作为参数传递(例如 all exclude(:foo))。

注意

你也可以将它与复合匹配器一起使用。

如果在检查集合的所有元素时提供的匹配器通过,则通过。

示例

expect([1, 3, 5]).to all be_odd
expect([1, 3, 6]).to all be_odd # fails
expect([1, 3, 5]).to all( be_odd.and be_an(Integer) )
662
663
664
# File 'lib/rspec/matchers.rb', line 662
def all(expected)
  BuiltIn::All.new(expected)
end

#be(*args) ⇒Object 也称为: a_value

给定 true、false 或 nil,如果实际值为 true、false 或 nil(分别),则将通过。给定无参数意味着调用者应该满足一个 if 条件(存在还是不存在)。

谓词是任何以“?”结尾并返回真或假的 Ruby 方法。给定 be_ 后面跟着任意谓词(不带“?”),RSpec 将匹配将其转换为对目标对象的查询。

任意谓词功能将处理以“be_an_”(例如 be_an_instance_of)、“be_a_”(例如 be_a_kind_of)或“be_”(例如 be_empty)为前缀的任何谓词,让您可以选择最适合谓词的前缀。

示例

expect(actual).to     be_truthy
expect(actual).to     be_falsey
expect(actual).to     be_nil
expect(actual).to     be_[arbitrary_predicate](*args)
expect(actual).not_to be_nil
expect(actual).not_to be_[arbitrary_predicate](*args)
349
350
351
# File 'lib/rspec/matchers.rb', line 349
def be(*args)
  args.empty? ? Matchers::BuiltIn::Be.new : equal(*args)
end

#be_a(klass) ⇒Object 也称为:be_an

如果 target.kind_of?(klass) 则通过。

355
356
357
# File 'lib/rspec/matchers.rb', line 355
def be_a(klass)
  be_a_kind_of(klass)
end

#be_a_kind_of(expected) ⇒Object 也称为:be_kind_of, a_kind_of

如果 actual.kind_of?(expected) 则通过。

示例

expect(5).to     be_a_kind_of(Integer)
expect(5).to     be_a_kind_of(Numeric)
expect(5).not_to be_a_kind_of(Float)
378
379
380
# File 'lib/rspec/matchers.rb', line 378
def be_a_kind_of(expected)
  BuiltIn::BeAKindOf.new(expected)
end

#be_an_instance_of(expected) ⇒Object 也称为:be_instance_of, an_instance_of

如果 actual.instance_of?(expected) 则通过。

示例

expect(5).to     be_an_instance_of(Integer)
expect(5).not_to be_an_instance_of(Numeric)
expect(5).not_to be_an_instance_of(Float)
366
367
368
# File 'lib/rspec/matchers.rb', line 366
def be_an_instance_of(expected)
  BuiltIn::BeAnInstanceOf.new(expected)
end

#be_between(min, max) ⇒Object 也称为:a_value_between

如果 actual.between?(min, max) 则通过。适用于任何 Comparable 对象,包括 String、Symbol、Time 或 Numeric(Fixnum、Bignum、Integer、Float、Complex 和 Rational)。

默认情况下,be_between 是包含的(即在给定最大值或最小值时通过),但您可以通过在匹配器后链接它来使其 exclusive

示例

expect(5).to      be_between(1, 10)
expect(11).not_to be_between(1, 10)
expect(10).not_to be_between(1, 10).exclusive
395
396
397
# File 'lib/rspec/matchers.rb', line 395
def be_between(min, max)
  BuiltIn::BeBetween.new(min, max)
end

#be_falseyObject 也称为:be_falsy, a_falsey_value, a_falsy_value

如果 actual 是假值(false 或 nil)则通过。

316
317
318
# File 'lib/rspec/matchers.rb', line 316
def be_falsey
  BuiltIn::BeFalsey.new
end

#be_nilObject 也称为:a_nil_value

如果 actual 是 nil 则通过。

324
325
326
# File 'lib/rspec/matchers.rb', line 324
def be_nil
  BuiltIn::BeNil.new
end

#be_truthyObject 也称为:a_truthy_value

如果 actual 是真值(除 false 或 nil 之外的任何值)则通过。

310
311
312
# File 'lib/rspec/matchers.rb', line 310
def be_truthy
  BuiltIn::BeTruthy.new
end

#be_within(delta) ⇒Object 也称为:a_value_within, within

如果 actual == expected +/- delta 则通过。

示例

expect(result).to     be_within(0.5).of(3.0)
expect(result).not_to be_within(0.5).of(3.0)
405
406
407
# File 'lib/rspec/matchers.rb', line 405
def be_within(delta)
  BuiltIn::BeWithin.new(delta)
end

#change(receiver = nil, message = nil, &block) ⇒Object 也称为:a_block_changing, changing

应用于 proc,指定其执行将导致某些值发生变化。

您可以传递receivermessage,或一个块,但不能两者兼有。

当传递一个块时,它必须使用 { ... } 格式,而不是 do/end,因为 { ... } 绑定到 change 方法,而 do/end 会错误地绑定到 expect(..).toexpect(...).not_to 方法。

您可以将以下任何内容链接到末尾以指定有关更改的详细信息

  • from
  • to

或任何一个

  • by
  • by_at_least
  • by_at_most

== 注意

在评估传递给 expect 的块之前和之后评估 receiver.messageblock。如果该值为同一个对象,则使用其之前/之后的 hash 值来查看它是否发生了变化。因此,您的对象需要正确实现 hash 才能与此匹配器一起正常工作。

expect( ... ).not_to change 支持指定 from 的形式(它指定您期望的起始不变值),但不支持后续调用 byby_at_leastby_at_mostto 的形式。

示例

expect {
  team.add_player(player)
}.to change(roster, :count)
expect {
  team.add_player(player)
}.to change(roster, :count).by(1)
expect {
  team.add_player(player)
}.to change(roster, :count).by_at_least(1)
expect {
  team.add_player(player)
}.to change(roster, :count).by_at_most(1)
string = "string"
expect {
  string.reverse!
}.to change { string }.from("string").to("gnirts")
string = "string"
expect {
  string
}.not_to change { string }.from("string")
expect {
  person.happy_birthday
}.to change(person, :birthday).from(32).to(33)
expect {
  employee.develop_great_new_social_networking_app
}.to change(employee, :title).from("Mail Clerk").to("CEO")
expect {
  doctor.leave_office
}.to change(doctor, :sign).from(/is in/).to(/is out/)
user = User.new(:type => "admin")
expect {
  user.symbolize_type
}.to change(user, :type).from(String).to(Symbol)

参数

  • receiver (Object) (默认为:nil)
  • message (Symbol) (默认为:nil)

    要发送给接收者的消息

492
493
494
# File 'lib/rspec/matchers.rb', line 492
def change(receiver=nil, message=nil, &block)
  BuiltIn::Change.new(receiver, message, &block)
end

#contain_exactly(*items) ⇒Object 也称为:a_collection_containing_exactly, containing_exactly

注意

这也可以使用 =~ 运算符与 should 一起使用,但 =~ 不支持 expect

如果 actual 包含所有预期的内容(无论顺序如何)则通过。这适用于集合。传入多个参数,只有当所有参数都存在于集合中时才会通过。

示例

expect([1, 2, 3]).to contain_exactly(1, 2, 3)
expect([1, 2, 3]).to contain_exactly(1, 3, 2)

另见

510
511
512
# File 'lib/rspec/matchers.rb', line 510
def contain_exactly(*items)
  BuiltIn::ContainExactly.new(items)
end

#cover(*values) ⇒Object 也称为:a_range_covering, covering

如果 actual 覆盖 expected 则通过。这适用于 Ranges。您还可以传入多个参数,只有当所有参数都存在于 Range 中时才会通过。

警告:: 仅限 Ruby >= 1.9

示例

expect(1..10).to     cover(5)
expect(1..10).to     cover(4, 6)
expect(1..10).to     cover(4, 6, 11) # fails
expect(1..10).not_to cover(11)
expect(1..10).not_to cover(5)        # fails
528
529
530
# File 'lib/rspec/matchers.rb', line 528
def cover(*values)
  BuiltIn::Cover.new(*values)
end

#end_with(*expected) ⇒Object 也称为:a_collection_ending_with, a_string_ending_with, ending_with

如果实际值以预期值结尾则匹配。对于字符串,匹配实际字符串的最后 expected.length 个字符。对于数组,匹配实际数组的最后 expected.length 个元素。

示例

expect("this string").to   end_with "string"
expect([0, 1, 2, 3, 4]).to end_with 4
expect([0, 2, 3, 4, 4]).to end_with 3, 4
543
544
545
# File 'lib/rspec/matchers.rb', line 543
def end_with(*expected)
  BuiltIn::EndWith.new(*expected)
end

#eq(expected) ⇒Object 也称为:an_object_eq_to, eq_to

如果通过actual == expected.

有关 Ruby 中相等性的更多信息,请参见 http://www.ruby-doc.org/core/classes/Object.html#M001057

示例

expect(5).to     eq(5)
expect(5).not_to eq(3)
558
559
560
# File 'lib/rspec/matchers.rb', line 558
def eq(expected)
  BuiltIn::Eq.new(expected)
end

#eql(expected) ⇒Object 也称为:an_object_eql_to, eql_to

如果 actual.eql?(expected) 则通过。

有关 Ruby 中相等性的更多信息,请参见 http://www.ruby-doc.org/core/classes/Object.html#M001057

示例

expect(5).to     eql(5)
expect(5).not_to eql(3)
572
573
574
# File 'lib/rspec/matchers.rb', line 572
def eql(expected)
  BuiltIn::Eql.new(expected)
end

#equal(expected) ⇒Object 也称为:an_object_equal_to, equal_to

如果通过actual.equal?(expected)(对象标识)。

有关 Ruby 中相等性的更多信息,请参见 http://www.ruby-doc.org/core/classes/Object.html#M001057

示例

expect(5).to       equal(5)   # Integers are equal
expect("5").not_to equal("5") # Strings that look the same are not the same object
586
587
588
# File 'lib/rspec/matchers.rb', line 586
def equal(expected)
  BuiltIn::Equal.new(expected)
end

#exist(*args) ⇒Object 也称为:an_object_existing, existing

如果 actual.exist?actual.exists? 则通过。

示例

expect(File).to exist("path/to/file")
596
597
598
# File 'lib/rspec/matchers.rb', line 596
def exist(*args)
  BuiltIn::Exist.new(*args)
end

#expectExpectations::ExpectationTarget

通过将 actual 包装在 ExpectationTarget 中来支持 expect(actual).to matcher 语法。

示例

expect(actual).to eq(expected)
expect(actual).not_to eq(expected)

返回值

另见


    
# File 'lib/rspec/matchers.rb', line 263

#have_attributes(expected) ⇒Object 也称为:an_object_having_attributes, having_attributes

注意

如果 actual 不响应任何预期的属性,则将失败。

如果 actual 的属性值与预期的属性哈希匹配,则通过。无论您如何定义属性读取器,这都适用。

示例

Person = Struct.new(:name, :age)
person = Person.new("Bob", 32)
expect(person).to have_attributes(:name => "Bob", :age => 32)
expect(person).to have_attributes(:name => a_string_starting_with("B"), :age => (a_value > 30) )
expect(person).to have_attributes(:color => "red")
616
617
618
# File 'lib/rspec/matchers.rb', line 616
def have_attributes(expected)
  BuiltIn::HaveAttributes.new(expected)
end

#include(*expected) ⇒Object 也称为:a_collection_including, a_string_including, a_hash_including, including

如果 actual 包含 expected 则通过。这适用于集合和字符串。您还可以传入多个参数,只有当所有参数都存在于集合中时才会通过。

示例

expect([1,2,3]).to      include(3)
expect([1,2,3]).to      include(2,3)
expect([1,2,3]).to      include(2,3,4) # fails
expect([1,2,3]).not_to  include(4)
expect("spread").to     include("read")
expect("spread").not_to include("red")
expect(:a => 1, :b => 2).to include(:a)
expect(:a => 1, :b => 2).to include(:a, :b)
expect(:a => 1, :b => 2).to include(:a => 1)
expect(:a => 1, :b => 2).to include(:b => 2, :a => 1)
expect(:a => 1, :b => 2).to include(:c) # fails
expect(:a => 1, :b => 2).not_to include(:a => 2)
639
640
641
# File 'lib/rspec/matchers.rb', line 639
def include(*expected)
  BuiltIn::Include.new(*expected)
end

#match(expected) ⇒Object 也称为:match_regex, an_object_matching, a_string_matching, matching

注意

match_regex 别名已弃用,不建议使用。它是在 2.12.1 中添加的,以便从自定义匹配器中使用它(由于自定义匹配器 DSL 在 2.x 中的评估方式,match 在那里无法使用),但在 3.x 中不再需要。

给定一个 RegexpString,如果 actual.match(pattern) 通过。给定一个任意的嵌套数据结构(例如数组和哈希),如果 expected === actual || actual == expected 对于每对元素都匹配则匹配。

示例

expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
expect(email).to match("@example.com")
hash = {
  :a => {
    :b => ["foo", 5],
    :c => { :d => 2.05 }
  }
}
expect(hash).to match(
  :a => {
    :b => a_collection_containing_exactly(
      a_string_starting_with("f"),
      an_instance_of(Integer)
    ),
    :c => { :d => (a_value < 3) }
  }
)
697
698
699
# File 'lib/rspec/matchers.rb', line 697
def match(expected)
  BuiltIn::Match.new(expected)
end

#match_array(items) ⇒Object 也称为:an_array_matching

contain_exactly 的另一种形式,它接受预期的内容作为一个单独的数组参数,而不是作为单独的项目展开。

示例

expect(results).to contain_exactly(1, 2)
# is identical to:
expect(results).to match_array([1, 2])

另见

715
716
717
# File 'lib/rspec/matchers.rb', line 715
def match_array(items)
  contain_exactly(*items)
end

#output(expected = nil) ⇒Object 也称为:a_block_outputting

注意

to_stdoutto_stderr 通过临时替换 $stdout$stderr 来工作,因此它们无法拦截显式使用 STDOUT/STDERR 或使用在匹配器使用之前存储的 $stdout/$stderr 的引用的流输出。

注意

to_stdout_from_any_processto_stderr_from_any_process 使用 Tempfiles,因此它们比 to_stdoutto_stderr 慢得多(约 30 倍)。

没有参数,如果块输出 to_stdoutto_stderr 则通过。对于字符串,如果块输出 to_stdoutto_stderr 的特定字符串则通过。对于正则表达式或匹配器,如果块输出 to_stdoutto_stderr 的与之匹配的字符串则通过。

要捕获来自任何生成的子进程的输出,请使用 to_stdout_from_any_processto_stderr_from_any_process。来自继承主进程的相应标准流的任何进程的输出将被捕获。

示例

expect { print 'foo' }.to output.to_stdout
expect { print 'foo' }.to output('foo').to_stdout
expect { print 'foo' }.to output(/foo/).to_stdout
expect { do_something }.to_not output.to_stdout
expect { warn('foo') }.to output.to_stderr
expect { warn('foo') }.to output('foo').to_stderr
expect { warn('foo') }.to output(/foo/).to_stderr
expect { do_something }.to_not output.to_stderr
expect { system('echo foo') }.to output("foo\n").to_stdout_from_any_process
expect { system('echo foo', out: :err) }.to output("foo\n").to_stderr_from_any_process
752
753
754
# File 'lib/rspec/matchers.rb', line 752
def output(expected=nil)
  BuiltIn::Output.new(expected)
end

#raise_error(error = BuiltIn::RaiseError::UndefinedValue, message = nil, &block) ⇒Object 也称为:raise_exception, a_block_raising, raising

没有参数,如果引发任何错误则匹配。对于命名错误,只有在引发该特定错误时才会匹配。对于命名错误和指定为字符串的消息,只有在两者都匹配时才会匹配。对于命名错误和指定为正则表达式的消息,只有在两者都匹配时才会匹配。传递一个可选的块以对匹配的异常执行额外的验证

示例

expect { do_something_risky }.to raise_error
expect { do_something_risky }.to raise_error(PoorRiskDecisionError)
expect { do_something_risky }.to raise_error(PoorRiskDecisionError) { |error| expect(error.data).to eq 42 }
expect { do_something_risky }.to raise_error { |error| expect(error.data).to eq 42 }
expect { do_something_risky }.to raise_error(PoorRiskDecisionError, "that was too risky")
expect { do_something_risky }.to raise_error(PoorRiskDecisionError, /oo ri/)
expect { do_something_risky }.to raise_error("that was too risky")
expect { do_something_risky }.not_to raise_error
773
774
775
# File 'lib/rspec/matchers.rb', line 773
def raise_error(error=BuiltIn::RaiseError::UndefinedValue, message=nil, &block)
  BuiltIn::RaiseError.new(error, message, &block)
end

#respond_to(*names) ⇒Object 也称为:an_object_responding_to, responding_to

如果目标对象响应所有提供的名称则匹配。名称可以是字符串或符号。

示例

expect("string").to respond_to(:length)
792
793
794
# File 'lib/rspec/matchers.rb', line 792
def respond_to(*names)
  BuiltIn::RespondTo.new(*names)
end

#respond_to?(method) ⇒布尔值

:nocov

返回值

  • (布尔值)
979
980
981
982
# File 'lib/rspec/matchers.rb', line 979
def respond_to?(method, *)
  method = method.to_s
  method =~ DYNAMIC_MATCHER_REGEX || super
end

#satisfy(description = nil, &block) ⇒Object 也称为:an_object_satisfying, satisfying

如果提交的块返回 true 则通过。将 target 产生到块中。

一般来说,应该将其视为在找不到其他方法来指定您希望指定的行为时的最后手段。

如果您确实发现自己处于这种情况下,您始终可以编写自定义匹配器,这可能会使您的规范更具表现力。

示例

expect(5).to satisfy { |n| n > 3 }
expect(5).to satisfy("be greater than 3") { |n| n > 3 }

参数

  • description (String) (默认为:nil)

    用于此匹配器的可选描述。

813
814
815
# File 'lib/rspec/matchers.rb', line 813
def satisfy(description=nil, &block)
  BuiltIn::Satisfy.new(description, &block)
end

#start_with(*expected) ⇒Object 也称为:a_collection_starting_with, a_string_starting_with, starting_with

如果实际值以预期值开头,则匹配。对于字符串,匹配实际字符串的前 expected.length 个字符。对于数组,匹配实际数组的前 expected.length 个元素。

示例

expect("this string").to   start_with "this s"
expect([0, 1, 2, 3, 4]).to start_with 0
expect([0, 2, 3, 4, 4]).to start_with 0, 1
828
829
830
# File 'lib/rspec/matchers.rb', line 828
def start_with(*expected)
  BuiltIn::StartWith.new(*expected)
end

#throw_symbol(expected_symbol = nil, expected_arg = nil) ⇒Object 也称为:a_block_throwing, throwing

如果没有参数,如果一个 proc 抛出任何 Symbol,则匹配。

给定一个 Symbol,如果给定的 proc 抛出指定的 Symbol,则匹配。

给定一个 Symbol 和一个参数,如果给定的 proc 抛出指定的 Symbol,并且带有指定的参数,则匹配。

示例

expect { do_something_risky }.to throw_symbol
expect { do_something_risky }.to throw_symbol(:that_was_risky)
expect { do_something_risky }.to throw_symbol(:that_was_risky, 'culprit')
expect { do_something_risky }.not_to throw_symbol
expect { do_something_risky }.not_to throw_symbol(:that_was_risky)
expect { do_something_risky }.not_to throw_symbol(:that_was_risky, 'culprit')
850
851
852
# File 'lib/rspec/matchers.rb', line 850
def throw_symbol(expected_symbol=nil, expected_arg=nil)
  BuiltIn::ThrowSymbol.new(expected_symbol, expected_arg)
end

#yield_controlObject 也称为:a_block_yielding_control, yielding_control

注意

你的 expect 块必须接受一个参数,并将其传递给被测方法作为块。

如果 expect 块中调用的方法执行了 yield,无论是否传递了参数,都通过。

示例

expect { |b| 5.tap(&b) }.to yield_control
expect { |b| "a".to_sym(&b) }.not_to yield_control
871
872
873
# File 'lib/rspec/matchers.rb', line 871
def yield_control
  BuiltIn::YieldControl.new
end

#yield_successive_args(*args) ⇒Object 也称为:a_block_yielding_successive_args, yielding_successive_args

注意

你的 expect 块必须接受一个参数,并将其传递给被测方法作为块。

专为与重复执行 yield 的方法(例如迭代器)一起使用而设计。如果 expect 块中调用的方法多次执行 yield,并且参数与给定的参数匹配,则通过。

参数匹配使用 ===(case 匹配运算符)和 == 进行。如果预期参数和实际参数与任一运算符匹配,则匹配器将通过。

示例

expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2])
expect { |b| [1, 2, 3].each(&b) }.not_to yield_successive_args(1, 2)
940
941
942
# File 'lib/rspec/matchers.rb', line 940
def yield_successive_args(*args)
  BuiltIn::YieldSuccessiveArgs.new(*args)
end

#yield_with_args(*args) ⇒Object 也称为:a_block_yielding_with_args, yielding_with_args

注意

你的 expect 块必须接受一个参数,并将其传递给被测方法作为块。

注意

此匹配器不适合与多次执行 yield 的方法一起使用。

如果没有参数,如果 expect 块中调用的方法执行了 yield,并且带有参数(无论参数是什么或有多少),则匹配。

如果提供了参数,如果 expect 块中调用的方法执行了 yield,并且带有与给定参数匹配的参数,则匹配。

参数匹配使用 ===(case 匹配运算符)和 == 进行。如果预期参数和实际参数与任一运算符匹配,则匹配器将通过。

示例

expect { |b| 5.tap(&b) }.to yield_with_args # because #tap yields an arg
expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5
expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5
expect { |b| File.open("f.txt", &b) }.to yield_with_args(/txt/) # because /txt/ === "f.txt"

expect { |b| User.transaction(&b) }.not_to yield_with_args # because it yields no args
expect { |b| 5.tap(&b) }.not_to yield_with_args(1, 2, 3)
919
920
921
# File 'lib/rspec/matchers.rb', line 919
def yield_with_args(*args)
  BuiltIn::YieldWithArgs.new(*args)
end

#yield_with_no_argsObject 也称为:a_block_yielding_with_no_args, yielding_with_no_args

注意

你的 expect 块必须接受一个参数,并将其传递给被测方法作为块。

注意

此匹配器不适合与多次执行 yield 的方法一起使用。

如果 expect 块中调用的方法执行了 yield,并且没有参数,则通过。如果未执行 yield,或执行了 yield 但带有参数,则失败。

示例

expect { |b| User.transaction(&b) }.to yield_with_no_args
expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5`
expect { |b| "a".to_sym(&b) }.not_to yield_with_no_args # because it does not yield
889
890
891
# File 'lib/rspec/matchers.rb', line 889
def yield_with_no_args
  BuiltIn::YieldWithNoArgs.new
end