RSpec: Stub private method

41,505

Solution 1

should_receive(:method) works whether the visibility of :method is public or private.

Solution 2

You can use allow_any_instance_of method to stub or mock any instance of a class for e.g. you have a class named Foo with some private methods than you can do something like this

allow_any_instance_of(Foo).to receive(:private_method) do
  #do something
end 

In case if there you have module also, you can do something like this

allow_any_instance_of(Module::Foo).to receive(:private_method) do
  #do something
end

You can find more details about allow_any_instance_of() method at Official Documentation

Solution 3

Why do you want to test the private methods? They're private for a reason; to prevent access from external calls. Testing the public methods that rely on the private methods should be sufficient.

Share:
41,505
23tux
Author by

23tux

Rails afficionado

Updated on July 17, 2022

Comments

  • 23tux
    23tux almost 2 years

    I try to test a class with RSpec2, that has some private methods, which are called from some public methods. I test the public methods with

    @foo.should_receive(:start_training).exactly(2).times
    

    if they are called and how often. My problem is, that this approach doesn't work with private methods. So, is there any way to use sth like @foo.send(:private_method) in combination with should_receive? Or any other syntax?

  • 23tux
    23tux about 11 years
    eehmm... I'm sure that it works. Can you explain it more what you mean?
  • 23tux
    23tux about 11 years
    I tried it out, when I try to call should_receive with a private method, I get private method start_training' called for #<Run:0x007f7f7e2ebe68>`
  • Justin Aiken
    Justin Aiken about 11 years
    Could you post a bit more code? In the spec I'm working on atm, I'm should_receive'ing private methods with no issues...
  • 23tux
    23tux about 11 years
    Silly me, I called the private method from another step of the test. So you were right, should_receive works in both cases, public AND private methods. Thanks!
  • André Herculano
    André Herculano about 10 years
    I'm pretty sure it worth it testing private methods. Otherwise, if you have 10 public methods that rely on that one private method, you could end up repeating yourself testing the behavior of all public those methods.
  • Damien Roche
    Damien Roche almost 9 years
    @AndréHerculano yes, but you should be testing behaviour, not implementation. You would test the returns of those public methods, regardless of what private methods they use.
  • 23tux
    23tux over 5 years
    using allow_any_instance_of is considered a bad practise, see rubydoc.info/gems/rubocop-rspec/1.6.0/RuboCop/Cop/RSpec/…
  • courtsimas
    courtsimas over 4 years
    They didn't say they wanted to test private methods. But the test relied on some private methods that he wanted to stub out.
  • 23tux
    23tux over 4 years
    as pointed out in the answer above, you can stub private methods, and it has nothing to do with protected methods. Furthermore stubbing with allow_any_instance_of is considered a code smell and should be avoided (also recommended by Rubocop rubydoc.info/gems/rubocop-rspec/1.6.0/RuboCop/Cop/RSpec/…)
  • A moskal escaping from Russia
    A moskal escaping from Russia over 4 years
    Why is it considered a smell @23tux?
  • Tim Kretschmer
    Tim Kretschmer about 3 years
    @SebastianPalma it's not. it's his opinion and the one of some rubocop fanatics. rubocop also say it's bad if your model in rails is > 250 lines (by default). some huge ass god models are easy 1000 and they are still slim. don't take rubocop for granted.