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.