Skip to main content

Type matchers

rspec-expectations includes two matchers to specify types of objects:

  • expect(obj).to be_kind_of(type): calls obj.kind_of?(type), which returns true if type is in obj's class hierarchy or is a module and is included in a class in obj's class hierarchy.
  • expect(obj).to be_instance_of(type): calls obj.instance_of?(type), which returns true if and only if type if obj's class.

Both of these matchers have aliases:

expect(obj).to be_a_kind_of(type)      # same as expect(obj).to be_kind_of(type)
expect(obj).to be_a(type) # same as expect(obj).to be_kind_of(type)
expect(obj).to be_an(type) # same as expect(obj).to be_kind_of(type)
expect(obj).to be_an_instance_of(type) # same as expect(obj).to be_instance_of(type)

With be_(a_)kind_of matcher

Given a file named "be_kind_of_matcher_spec.rb" with:

module MyModule; end

class Float
include MyModule
end

RSpec.describe 17.0 do
# the actual class
it { is_expected.to be_kind_of(Float) }
it { is_expected.to be_a_kind_of(Float) }
it { is_expected.to be_a(Float) }

# the superclass
it { is_expected.to be_kind_of(Numeric) }
it { is_expected.to be_a_kind_of(Numeric) }
it { is_expected.to be_an(Numeric) }

# an included module
it { is_expected.to be_kind_of(MyModule) }
it { is_expected.to be_a_kind_of(MyModule) }
it { is_expected.to be_a(MyModule) }

# negative passing case
it { is_expected.not_to be_kind_of(String) }
it { is_expected.not_to be_a_kind_of(String) }
it { is_expected.not_to be_a(String) }

# deliberate failures
it { is_expected.not_to be_kind_of(Float) }
it { is_expected.not_to be_a_kind_of(Float) }
it { is_expected.not_to be_a(Float) }
it { is_expected.not_to be_kind_of(Numeric) }
it { is_expected.not_to be_a_kind_of(Numeric) }
it { is_expected.not_to be_an(Numeric) }
it { is_expected.not_to be_kind_of(MyModule) }
it { is_expected.not_to be_a_kind_of(MyModule) }
it { is_expected.not_to be_a(MyModule) }
it { is_expected.to be_kind_of(String) }
it { is_expected.to be_a_kind_of(String) }
it { is_expected.to be_a(String) }
end

When I run rspec be_kind_of_matcher_spec.rb

Then the output should contain all of these:

| 24 examples, 12 failures | | expected 17.0 not to be a kind of Float | | expected 17.0 not to be a kind of Numeric | | expected 17.0 not to be a kind of MyModule | | expected 17.0 to be a kind of String |

With be_(an_)instance_of matcher

Given a file named "be_instance_of_matcher_spec.rb" with:

module MyModule; end

class Float
include MyModule
end

RSpec.describe 17.0 do
# the actual class
it { is_expected.to be_instance_of(Float) }
it { is_expected.to be_an_instance_of(Float) }

# the superclass
it { is_expected.not_to be_instance_of(Numeric) }
it { is_expected.not_to be_an_instance_of(Numeric) }

# an included module
it { is_expected.not_to be_instance_of(MyModule) }
it { is_expected.not_to be_an_instance_of(MyModule) }

# another class with no relation to the subject's hierarchy
it { is_expected.not_to be_instance_of(String) }
it { is_expected.not_to be_an_instance_of(String) }

# deliberate failures
it { is_expected.not_to be_instance_of(Float) }
it { is_expected.not_to be_an_instance_of(Float) }
it { is_expected.to be_instance_of(Numeric) }
it { is_expected.to be_an_instance_of(Numeric) }
it { is_expected.to be_instance_of(MyModule) }
it { is_expected.to be_an_instance_of(MyModule) }
it { is_expected.to be_instance_of(String) }
it { is_expected.to be_an_instance_of(String) }
end

When I run rspec be_instance_of_matcher_spec.rb

Then the output should contain all of these:

| 16 examples, 8 failures | | expected 17.0 not to be an instance of Float | | expected 17.0 to be an instance of Numeric | | expected 17.0 to be an instance of MyModule | | expected 17.0 to be an instance of String |