RSpec: Expecting non-primitive objects as method invocation arguments

Updated . Posted . Visible to the public. Repeats.

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.

Henning Koch
Last edit
Dominik Schöler
Attachments
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2016-05-13 06:51)