Heads up: expect(object).to receive(:method_name) does not execute the original implementation of the method

Updated . Posted . Visible to the public.

Let's assume that we have a model Movie that registers a callback function when a new instance of Movie is created (Note: For the purpose of this card it is not important what that callback does or which type of callback it is).

This is how we test whether the callback function (here it is named :my_method) is called when a new movie is created:

expect_any_instance_of(Movie).to receive(:my_method)
create(:movie)  # <-- this is where the method :my_method should be called

You might expect that when calling create(:movie), the callback function will be executed and whatever it does will happen and will have effect. But what we can observe is that the behaviour of the callback function :my_method does not happen in the test, as if the callback function is not executed in the test. However, since the test does not fail, the method :my_method must have been called during the test.

Why is that? It is because of how receive(:my_method) works. We can think of it like this: receive() replaces the original method :my_method with a new implementation, remembering only that this method was called in the code. But the original implementation of the method :my_method is overwritten in the test and thus not executed.

But what if I want to run the original implementation of the method :my_method?
For this there is and_call_original (docs):

expect_any_instance_of(Movie).to receive(:my_method).and_call_original
create(:movie)  # <-- this is where the method :my_method should be called

This will execute the original implementation (see here Show archive.org snapshot ).

Last edit
Jonas Schiele
License
Source code in this card is licensed under the MIT License.
Posted to makandra dev (2023-01-24 12:44)