メインコンテンツまでスキップ

respond_to マッチャー

respond_to マッチャーを使用して、オブジェクトのインターフェースの詳細を指定します。基本的な形式は次のとおりです:

expect(obj).to respond_to(:foo) # obj.respond_to?(:foo) が true の場合にパスする

マッチャーに複数の引数を渡すことで、オブジェクトが複数のメッセージに応答することを指定することもできます:

expect(obj).to respond_to(:foo, :bar) # obj.respond_to?(:foo) && obj.respond_to?(:bar) が true の場合にパスする

メソッドが受け入れる引数の数が重要な場合は、それも指定することができます:

expect(obj).to respond_to(:foo).with(1).argument
expect(obj).to respond_to(:bar).with(2).arguments
expect(obj).to respond_to(:baz).with(1..2).arguments
expect(obj).to respond_to(:xyz).with_unlimited_arguments

Rubyのバージョンがキーワード引数をサポートしている場合、メソッドが受け入れるキーワードのリストを指定することができます。

expect(obj).to respond_to(:foo).with_keywords(:ichi, :ni)
expect(obj).to respond_to(:bar).with(2).arguments.and_keywords(:san, :yon)
expect(obj).to respond_to(:baz).with_arbitrary_keywords

このマッチャーは完全に #respond_to? に依存していることに注意してください。オブジェクトが #method_missing を介して動的にメッセージに応答するが、#respond_to? を介してこれを示さない場合、このマッチャーは誤った結果を返します。

基本的な使用法

次の内容で "respond_to_matcher_spec.rb" という名前のファイルがあるとします:

RSpec.describe "a string" do
it { is_expected.to respond_to(:length) }
it { is_expected.to respond_to(:hash, :class, :to_s) }
it { is_expected.not_to respond_to(:to_model) }
it { is_expected.not_to respond_to(:compact, :flatten) }

# deliberate failures
it { is_expected.to respond_to(:to_model) }
it { is_expected.to respond_to(:compact, :flatten) }
it { is_expected.not_to respond_to(:length) }
it { is_expected.not_to respond_to(:hash, :class, :to_s) }

# mixed examples--String responds to :length but not :flatten
# both specs should fail
it { is_expected.to respond_to(:length, :flatten) }
it { is_expected.not_to respond_to(:length, :flatten) }
end

rspec respond_to_matcher_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 10 の例、6 の失敗 | | "a string" が :to_model に応答することを期待しました | | "a string" が :compact, :flatten に応答することを期待しました | | "a string" が :length に応答しないことを期待しました | | "a string" が :hash, :class, :to_s に応答しないことを期待しました | | "a string" が :flatten に応答することを期待しました | | "a string" が :length に応答しないことを期待しました |

引数の指定

次の内容で "respond_to_matcher_argument_checking_spec.rb" という名前のファイルがあるとします:

RSpec.describe 7 do
it { is_expected.to respond_to(:zero?).with(0).arguments }
it { is_expected.not_to respond_to(:zero?).with(1).argument }

it { is_expected.to respond_to(:between?).with(2).arguments }
it { is_expected.not_to respond_to(:between?).with(7).arguments }

# deliberate failures
it { is_expected.to respond_to(:zero?).with(1).argument }
it { is_expected.not_to respond_to(:zero?).with(0).arguments }

it { is_expected.to respond_to(:between?).with(7).arguments }
it { is_expected.not_to respond_to(:between?).with(2).arguments }
end

rspec respond_to_matcher_argument_checking_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 8 例、4 失敗 | | 7 に対して :zero? メソッドが 1 つの引数で呼び出されることを期待しています | | 7 に対して :zero? メソッドが 0 個の引数で呼び出されないことを期待しています | | 7 に対して :between? メソッドが 7 個の引数で呼び出されることを期待しています | | 7 に対して :between? メソッドが 2 個の引数で呼び出されないことを期待しています |

引数の範囲を指定する

以下の内容で "respond_to_matcher_argument_range_checking_spec.rb" という名前のファイルを作成します:

class MyClass
def build(name, options = {})
end

def inspect
'my_object'
end
end

RSpec.describe MyClass do
it { is_expected.to respond_to(:build).with(1..2).arguments }
it { is_expected.not_to respond_to(:build).with(0..1).arguments }
it { is_expected.not_to respond_to(:build).with(2..3).arguments }
it { is_expected.not_to respond_to(:build).with(0..3).arguments }

# deliberate failures
it { is_expected.not_to respond_to(:build).with(1..2).arguments }
it { is_expected.to respond_to(:build).with(0..1).arguments }
it { is_expected.to respond_to(:build).with(2..3).arguments }
it { is_expected.to respond_to(:build).with(0..3).arguments }
end

rspec respond_to_matcher_argument_range_checking_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 8 例、4 失敗 | | my_object に対して 1 〜 2 個の引数で :build メソッドが呼び出されないことを期待しています | | my_object に対して 0 〜 1 個の引数で :build メソッドが呼び出されることを期待しています | | my_object に対して 2 〜 3 個の引数で :build メソッドが呼び出されることを期待しています | | my_object に対して 0 〜 3 個の引数で :build メソッドが呼び出されることを期待しています |

無制限の引数を指定する

以下の内容で "respond_to_matcher_unlimited_argument_checking_spec.rb" という名前のファイルを作成します:

class MyClass
def greet(message = 'Hello', *people)
end

def hail(person)
end

def inspect
'my_object'
end
end

RSpec.describe MyClass do
it { is_expected.to respond_to(:greet).with_unlimited_arguments }
it { is_expected.to respond_to(:greet).with(1).argument.and_unlimited_arguments }
it { is_expected.not_to respond_to(:hail).with_unlimited_arguments }
it { is_expected.not_to respond_to(:hail).with(1).argument.and_unlimited_arguments }

# deliberate failures
it { is_expected.not_to respond_to(:greet).with_unlimited_arguments }
it { is_expected.not_to respond_to(:greet).with(1).argument.and_unlimited_arguments }
it { is_expected.to respond_to(:hail).with_unlimited_arguments }
it { is_expected.to respond_to(:hail).with(1).argument.and_unlimited_arguments }
end

rspec respond_to_matcher_unlimited_argument_checking_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 8 例、4 失敗 | | my_object に対して無制限の引数で :greet メソッドが呼び出されないことを期待しています | | my_object に対して 1 つの引数と無制限の引数で :greet メソッドが呼び出されないことを期待しています | | my_object に対して無制限の引数で :hail メソッドが呼び出されることを期待しています | | my_object に対して 1 つの引数と無制限の引数で :hail メソッドが呼び出されることを期待しています |

キーワードを指定する

以下の内容で "respond_to_matcher_keyword_checking_spec.rb" という名前のファイルを作成します:

class MyClass
def find(name = 'id', limit: 1_000, offset: 0)
[]
end

def inspect
'my_object'
end
end

RSpec.describe MyClass do
it { is_expected.to respond_to(:find).with_keywords(:limit, :offset) }
it { is_expected.to respond_to(:find).with(1).argument.and_keywords(:limit, :offset) }

it { is_expected.not_to respond_to(:find).with_keywords(:limit, :offset, :page) }
it { is_expected.not_to respond_to(:find).with(1).argument.and_keywords(:limit, :offset, :page) }

# deliberate failures
it { is_expected.to respond_to(:find).with_keywords(:limit, :offset, :page) }
it { is_expected.to respond_to(:find).with(1).argument.and_keywords(:limit, :offset, :page) }

it { is_expected.not_to respond_to(:find).with_keywords(:limit, :offset) }
it { is_expected.not_to respond_to(:find).with(1).argument.and_keywords(:limit, :offset) }
end

rspec respond_to_matcher_keyword_checking_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 8 例、4 失敗 | | my_object に対して :limit:offset:page のキーワードを指定して :find メソッドが呼び出されることを期待しています | | my_object に対して 1 つの引数と :limit:offset:page のキーワードを指定して :find メソッドが呼び出されることを期待しています | | my_object に対して :limit:offset のキーワードを指定して :find メソッドが呼び出されないことを期待しています | | my_object に対して 1 つの引数と :limit:offset のキーワードを指定して :find メソッドが呼び出されないことを期待しています |

キーワードを指定する

ファイル名が "respond_to_matcher_any_keywords_checking_spec.rb" の場合、以下の内容を持つとします:

class MyClass
def build(name: 'object', **opts)
end

def create(name: 'object', type: String)
end

def inspect
'my_object'
end
end

RSpec.describe MyClass do
it { is_expected.to respond_to(:build).with_any_keywords }
it { is_expected.to respond_to(:build).with_keywords(:name).and_any_keywords }
it { is_expected.not_to respond_to(:create).with_any_keywords }
it { is_expected.not_to respond_to(:create).with_keywords(:name).and_any_keywords }

# deliberate failures
it { is_expected.not_to respond_to(:build).with_any_keywords }
it { is_expected.not_to respond_to(:build).with_keywords(:name).and_any_keywords }
it { is_expected.to respond_to(:create).with_any_keywords }
it { is_expected.to respond_to(:create).with_keywords(:name).and_any_keywords }
end

rspec respond_to_matcher_any_keywords_checking_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 8 つの例、4 つの失敗 | | :build にキーワードを含まないように my_object が応答しないことが期待されます | | :name とキーワードを含むように :build に my_object が応答しないことが期待されます | | :create にキーワードを含むように my_object が応答することが期待されます | | :name とキーワードを含むように :create に my_object が応答することが期待されます |

必須キーワードを指定する

ファイル名が "respond_to_matcher_required_keyword_checking_spec.rb" の場合、以下の内容を持つとします:

class MyClass
def plant(seed:, fertilizer: nil, water: 'daily')
[]
end

def inspect
'my_object'
end
end

RSpec.describe MyClass do
it { is_expected.to respond_to(:plant).with_keywords(:seed) }
it { is_expected.to respond_to(:plant).with_keywords(:seed, :fertilizer, :water) }
it { is_expected.not_to respond_to(:plant).with_keywords(:fertilizer, :water) }

# deliberate failures
it { is_expected.not_to respond_to(:plant).with_keywords(:seed) }
it { is_expected.not_to respond_to(:plant).with_keywords(:seed, :fertilizer, :water) }
it { is_expected.to respond_to(:plant).with_keywords(:fertilizer, :water) }
end

rspec respond_to_matcher_required_keyword_checking_spec.rb を実行すると、

以下のすべてが出力に含まれるはずです:

| 6 つの例、3 つの失敗 | | :seed をキーワードとして含むように my_object が応答しないことが期待されます | | :seed, :fertilizer, :water をキーワードとして含むように my_object が応答しないことが期待されます | | :fertilizer:water をキーワードとして含むように my_object が応答することが期待されます |