Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

[have_receive] (not have_receive"d") will return true no matter what #1288

Closed
github0013 opened this issue Aug 17, 2019 · 5 comments
Closed
Assignees

Comments

@github0013
Copy link

Subject of the issue

Calling have_receive always become true. (not have_receive[d])

have_receive, does this matcher method exist?
https://relishapp.com/rspec/rspec-mocks/docs/basics/spies
I only see have_receive[d]

Your environment

  • ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin16]
  • rspec-mocks (3.8.1)

Steps to reproduce

describe :have_receive do
  let(:object) { spy(:object) }

  it do
    object.some_method
    # This is expected to be true 
    expect(object).to have_received(:some_method)
  end

  # This is expected to be false, but is true, and it doesn't even raise an error  for `have_receive`
  it { expect(object).to have_receive(:method_never_called) }
end

Expected behavior

    # This should not pass or should raise an error for the method missing?
    it { expect(object).to have_receive(:never_exist_method) } 

Actual behavior

    # This passes, when it shouldn't
    it { expect(object).to have_receive(:never_exist_method) } 
@github0013 github0013 changed the title [have_receive] (not [have_receive"d"]) will return true no matter what [have_receive] (not have_receive"d") will return true no matter what Aug 17, 2019
@JonRowe
Copy link
Member

JonRowe commented Aug 19, 2019

👋 Hi, you've fallen victim to a typo leading you to a strange inconsistency.

Whats happening here...

  1. A spy returns true for any method by default.
  2. have_... is a special matcher checking for the method name after the _ as a predicate, e.g. recieve? in this case.
  3. The spy returns true for receive?, the matcher is therefore satisfied, the test passes.

A work arounds to avoid this is to use a verifying double rather than a normal spy, which would then recognise the non existant method and help highlight the issue.

I think a proper fix is needed here too, but that will require us detecting spys in the magic matcher and special casing them, WDYT @benoittgt

@benoittgt
Copy link
Member

Thanks for your issue @github0013

I think a proper fix is needed here too, but that will require us detecting spys in the magic matcher and special casing them, WDYT @benoittgt

I don't see exactly what you mean here. Isn't breaking the contract of spy?

# Constructs a test double that is optimized for use with
# `have_received`. With a normal double one has to stub methods in order
# to be able to spy them. A spy automatically spies on all methods.
def spy(*args)
double(*args).as_null_object
end

@JonRowe
Copy link
Member

JonRowe commented Aug 20, 2019

@benoittgt have_receive is a typo, but its picked up as have_<predicate> using RSpec::Expectations::Has, the spy by design responds to all methods in order to work, but in this case it cases a false positive pass.

@benoittgt benoittgt self-assigned this Aug 20, 2019
@nevinera
Copy link
Contributor

nevinera commented May 7, 2024

As with #1132, I think this might be closeable now - the actual behavior is still there, but the problem case now causes:

expected #<Double "thing">.has_recieveddddddd?(:foo) to return false, got #<Double "thing">

At some point in the last four years, the matcher started checking for true/false, instead of truthy/falsey values.

Edit: As pointed out here, this was from the strict_predicate_matchers, which is enabled in this repo, but not by default. I have what I think is a resolution in rspec/rspec-expectations#1455

@JonRowe
Copy link
Member

JonRowe commented May 8, 2024

I'm closing this one in favour of #1132

@JonRowe JonRowe closed this as completed May 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants