Jon Rowe,

My test looked something like this:

class MyObject
  def call
    do_something
  end

private

  def do_something # this used to be public!
    #...
  end
end

subject { MyObject.new }

expect(obj).to receive(:do_something)
subject.call # this calls do_something

Regardless of whether do_something is public or private, the expectation 
passes, but when called outside of a test, the method fails with 
NoMethodError because the method became private. I totally agree that the 
tests we had were not adequate, but also it wasn't something we were able 
to catch.

Daniel

On Tuesday, July 21, 2020 at 4:01:04 PM UTC-4 Jon Rowe wrote:

> Hi Daniel
>
> rspec-mocks does not change the visibility of methods when mocking them, 
> this means that your method here should have remained private when you 
> change it, and should have resulted in a `NoMethodError` if called directly 
> for example:
>
> class MyClass
>   Yarr = "Yarr"
>
>   def good_ship?
>     pirate_method != Yarr
>   end
>
>   private
>
>   def pirate_method
>     Yarr
>   end
> end
>
> RSpec.describe "privacy" do
>   let(:object) { MyClass.new }
>
>   it "works with private methods" do
>     expect(object).to receive(:pirate_method) { "We're a good ship" }
>     expect(object.good_ship?).to eq true
>   end
>
>   it "works with pirate methods" do
>     expect(object).to receive(:pirate_method) { "We're a good ship... 
> honest" }
>     object.pirate_method
>   end
> end
>
>
> The first spec passes because pirate_method, although private, is called 
> from an internal construct, and is thus allowed and verifying.
>
> The second spec fails with:
>
> NoMethodError:
>        private method `pirate_method' called for 
> #<MyClass:0x00007fd1a8a50650>
>
> And if you stub it, it will actually say it failed to be called even if 
> you try to call it.
>
> So if you experienced the change somehow silently breaking your tests, 
> chances are any additional checks we could do, would also not help…
>
> Can you share a more specific example?
>
> Cheers
> Jon Rowe
> ---------------------------
> [email protected]
> jonrowe.co.uk
>
> On 21 July 2020 at 19:30, 'Daniel Vandersluis' via rspec wrote:
>
> We recently accidentally moved a method from public to private and it was 
> not caught by our test suite because expect(obj).to receive(:method) 
> succeeds regardless of whether or not obj.method is actually accessible 
> or not.
>
> I'm not sure if there's an easy way to get around this (because it should 
> be possible to stub out private methods of course). I can't think off hand 
> of a way to determine if the object has access to a method without calling 
> it, which obviously an expectation shouldn't be doing generally. Maybe we 
> can check if the receiver is self?
>
> If there's a way to do this, it'd be nice to have this as a configuration 
> option!
>
> Thanks,
> Daniel Vandersluis
>
>

-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rspec/bc621ff0-33d9-4302-9791-1d43704b8937n%40googlegroups.com.

Reply via email to