Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In RSpec, what is the difference between a message expectation (receive) and a test spy (have_received)?

In RSpec (specifically rspec-mocks), what is the difference between Message Expectations and Test Spies? They seem similar, and appear right next to each other as seperate sections in the readme.

i.e. what is the difference between:

expect(validator).to receive(:validate) # message expectation

and

expect(validator).to have_received(:validate) # test spy
like image 965
ben Avatar asked Jan 18 '14 22:01

ben


People also ask

What is Spy in RSpec?

Spies are an alternate type of test double that support this. pattern by allowing you to expect that a message has been received after the fact, using. have_received . You can use any test double (or partial double) as a spy, but the double must be setup to. spy on the messages you care about.

What is mock in RSpec?

What is a mock in RSpec? (Or a mock in general, because this isn't a concept unique to RSpec.) A mock is an object used for testing. You use mocks to test the interaction between two objects. Instead of testing the output value, like in a regular expectation.

What is double in RSpec?

RSpec features doubles that can be used as 'stand-ins' to mock an object that's being used by another object. Doubles are useful when testing the behaviour and interaction between objects when we don't want to call the real objects - something that can take time and often has dependencies we're not concerned with.

What is let in Ruby?

Use let to define a memoized helper method. The value will be cached. across multiple calls in the same example but not across examples. Note that let is lazy-evaluated: it is not evaluated until the first time. the method it defines is invoked.


2 Answers

Message expectations can be set on any object and represent a declaration that something is going to happen (or not happen) to that object in the future. If the expectation is violated during subsequent test execution, the test will fail at the time the violation occurs. If the expectation has not been met by the end of the test, the test will fail as well.

The have_received family of methods only works on test doubles and examines what has happened to the double in the past, from the time of the double's creation up through the current method call. It succeeds or fails at that point in time. The term "test spy" is a little misleading, because the support for this backward-looking mechanism is a standard part of rspec-mocks at this point. You don't do anything "special" to create a "test spy".

like image 145
Peter Alfvin Avatar answered Sep 26 '22 11:09

Peter Alfvin


You can't always use spies when you test, basically for expectations on classes.

Example:

expect(User).to receive(:new)

there is no way to do this with a spy (unless you do dependency injection).

Now, you could do the following:

user = double('user', save: true)
expect(User).to receive(:new).and_return user

User.new.save

expect(user).to have_received(:save)

You see clearly that:

  • you have to set expectations on real object before you run the real code (it kind of looks weird to set expectations before triggering the code)

  • you can set expectation on spies after the real code, which is more natural

like image 37
apneadiving Avatar answered Sep 24 '22 11:09

apneadiving