How do you expect a message to be sent to any instance of a class (twice the size) with specific arguments in Rails?

When returning an order, we need to deactivate the serial files attached to this order. In the spec the order has two serials, ergo, I should expect two API calls that will take care of deactivating the serials.

I tried:

expect_any_instance_of(Gateway).to receive(:deactivate_dongle).once.with(serial_number: '67890')
expect_any_instance_of(Gateway).to receive(:deactivate_dongle).once.with(serial_number: '12345')

      

Which gives me:

The message 'deactivate_dongle' was received by #<Gateway:70179265658480 @connection=#<Faraday::Connection:0x007fa7c4667b28>> but has already been received by #<Gateway:0x007fa7c6858160>

      

The same for:

expect_any_instance_of(Gateway).to receive(:deactivate_dongle).with(serial_number: '12345')
expect_any_instance_of(Gateway).to receive(:deactivate_dongle).with(serial_number: '67890')

      

How can I achieve this?

+3


source to share


2 answers


If you can change your implementation to live up to the expectations of a known instance Gateway

(to avoid expect_any_instance_of

), you can use rspec ordered

to add restrictions on receiving messages.

I am afraid that in your case you should try to add a BOM where there is only one of these serials so you can expect it correctly. eg.



expect_any_instance_of(Gateway).to receive(:deactivate_dongle).once.with(serial_number: '67890')

      

And then you have a spec with n serials and just expect to deactivate_dongle

be called n times.

+2


source


I think you want a Null Object :

Use the as_null_object method to ignore any messages that are not explicitly set as stubs or wait messages.

allow_any_instance_of(JarvisGateway).to receive(:deactivate_dongle).as_null_object

      


Here is another solution I was thinking about before I found the solution above. Blocks offer more flexibility in argument validation than built-in blocks. See Use a block to validate arguments .



allow_any_instance_of(JarvisGateway).to receive(:deactivate_dongle) do |args|
  expect(['67890', '12345']).to include args[:serial_number]
end

expect_any_instance_of(JarvisGateway).to receive(:deactivate_dongle).twice

      


Not sure what allow_any_instance_of

supports blocks this way.
If it is not, you can do it by one or more of the following:

  • Create an instance JarvisGateway

    and check the sent messages instead allow_any_instance_of

    .
  • Use has_received

    instead to receive

    . See Spies .


EDIT: expect_any_instance_of(JarvisGateway).to receive(:deactivate_dongle).twice

Not really that good because it doesn't check to make sure every serial number is called once.

+1


source







All Articles