Expecting a primitive value as an argument to a method invocation is easy:
expect(object).to receive(:foo).with('arg1', 'arg2')
This expectation would be met with this call:
object.foo('arg1', 'arg2')
But what if the argument is expected to be an object with a given set of methods? E.g. this class with #first_name
and #last_name
methods:
class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
attr_reader :first_name, :last_name
end
To just test if an argument is a Person
, you have several options:
Test that the argument is an instance of a certain class
expect(object).to receive(:foo).with(instance_of(Person))
Test that the argument responds to certain methods
expect(object).to receive(:foo).with(duck_type(:first_name, :last_name))
To also test that the methods return a particular value, use have_attributes
:
expect(object).to receive(:foo).with(have_attributes(first_name: 'Hans', last_name: 'Dampf'))
Test that the argument is a certain class and also returns certain values
Use the attached object_having
matcher to test both class and method return values:
expect(object).to receive(:foo).with(object_having(Person, first_name: 'Hans', last_name: 'Dampf'))
Test that the argument is equal to another object
Since with
tests ==
equality by default, you might want to define Person#==
so you can compare it to other persons:
class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def ==(other)
first_name == other.first_name && last_name == other.last_name
end
end
Then, in your spec:
expect(object).to receive(:foo).with(Person.new(first_name: 'Hans', last_name: 'Dampf'))
Test anything you want with a block
expect(object).to receive(:foo).with do |received_object|
expect(received_object.first_name).to eq('Hans')
...
end
See Rspec: Complex argument expectations for should_receive for more details.
Posted by Henning Koch to makandra dev (2016-05-13 06:51)