Retrieve list of calls received by a spy in have_received matcher

28 views
Skip to first unread message

Luc Delmon

unread,
Nov 20, 2020, 4:10:27 AM11/20/20
to rspec
Hi,

I have a problem that got me stucks for hour now. I do not think that it's that hard. I'm just unable to find the correct documentation

Given this example.

it 'test' do
  obj = double()
  allow(obj).to receive(:a)

  obj.a(:arg_1)
  obj.a(:arg_2)

  expect(obj).to(
    have_received(:a).with(:arg_3)
  )
end

rspec will give me a nice error with the list of args received

#<Double (anonymous)> received :a with unexpected arguments
         expected: (:arg_3)
              got: (:arg_1) (1 time)
                      (:arg_2) (1 time)

whih is very nice. Now if I change a bit the test

it 'test' do
  obj = double()
  allow(obj).to receive(:a)

  obj.a(:arg_1)
  obj.a(:arg_2)

  expect(obj).to(
    have_received(:a).with(:arg_2).twice
  )
end

I have a new error message without the call list
  (Double (anonymous)).a(:arg_2)
           expected: 2 times with arguments: (:arg_2)
           received: 1 time with arguments: (:arg_2)

No problem I can choose my to make my own custom message

expect(obj).to(
have_received(:a).with(:arg_2).twice,
"#{??}"
)

But how can I retrieve the call list used un the first case? Do I have to call it from obj ? Or since I have acces to the matcher instance. I can call a method to retrieve it ?

If you can help me or point me in the right direction I would be really thankfull.




Phil Pirozhkov

unread,
Nov 20, 2020, 2:32:50 PM11/20/20
to Jack Royal-Gordon
Luc,

There's no way you can get this information using this syntax, since by the moment `"#{??}"` is evaluated, `have_received`'s `matches?` has not yet been called.
expect(obj).to(
have_received(:a).with(:arg_2).twice,
"#{??}"
)

There, you can use `::RSpec::Mocks.space.proxy_for(a)` and poke around its `@messages_received`.

So, for:
```
  it {
    a = double
    allow(a).to receive(:foo)
    a.foo(1)
    expect(a).to have_received(:foo).twice, lambda {
      puts ::RSpec::Mocks.space.proxy_for(a).instance_variable_get(:@messages_received)
    }
  }
```
you'll get:
```
[[:foo, [1], nil]]
```

Luc Delmon

unread,
Nov 23, 2020, 4:29:15 AM11/23/20
to rspec
Well,

I think it's even better. If I can access @message_received at any time after defining the spy. I might change the matcher itself to iterate over the list directly. It match more with my objectives.

thank you

Phil Pirozhkov

unread,
Nov 23, 2020, 5:44:08 AM11/23/20
to Jack Royal-Gordon
Luc,

Please keep in mind that you are dealing with the private API, and it might change even in with a minor RSpec version update.

--
You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/09b204c4-5392-4f74-8903-6e95ad57777bn%40googlegroups.com.

Luc Delmon

unread,
Nov 23, 2020, 6:28:40 AM11/23/20
to rspec
Thanks for the warning,

We isolate gem updates PR.

Since it's a matcher, Test would broke but I would only have one correction to do so I guess it's ok for now.
Reply all
Reply to author
Forward
0 new messages