How to spec a private method

Ruby on-RailsRspec

Ruby on-Rails Problem Overview


I got a model with a private method I'd like to spec with RSpec,
how do you usually do ? Do you only test the method calling the private one ?
or also spec the private one ? if so, how do you do ?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

I always take this approach: I want to test the public API my class exposes.

If you have private methods, you only call them from the public methods you expose to other classes. Hence, if you test that those public methods work as expected under all conditions, you have also proven that the private methods they use work as well.

I'll admit that I've come across some especially complex private methods. In that extreme case you want to test them, you can do this:

@obj.send(:private_method)

Solution 2 - Ruby on-Rails

For the private methods that need code coverage (either temporarily or permanently), use the rspec-context-private gem to temporarily make private methods public within a context.

gem 'rspec-context-private'

It works by adding a shared context to your project.

RSpec.shared_context 'private', private: true do

  before :all do
    described_class.class_eval do
      @original_private_instance_methods = private_instance_methods
      public *@original_private_instance_methods
    end
  end

  after :all do
    described_class.class_eval do
      private *@original_private_instance_methods
    end
  end

end

Then, if you pass :private as metadata to a describe block, the private methods will be public within that context.

class Example
  private def foo
    'bar'
  end
end

describe Example, :private do
  it 'can test private methods' do
    expect(subject.foo).not eq 'bar'
  end
end

Solution 3 - Ruby on-Rails

If you're wanting to test an expectation on a private method, the accepted answer won't really work (at least not that I know of, so I'm open to correction on that point). What I've done instead is even filthier - in the test itself, just expose the method by redefining it:

def object_to_test.my_private_method
  super
end

Works on Ruby 1.8, can't comment on any of the newer runtimes.

Solution 4 - Ruby on-Rails

create a dummy class and access private method using .send(:private_method, args)

example

obj = Class.new { extend Classname } obj.send(:sum, 1,2)

obj = Class.new { extend Classname } obj.send(:sum)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMikeView Question on Stackoverflow
Solution 1 - Ruby on-RailsAriejanView Answer on Stackoverflow
Solution 2 - Ruby on-RailsbarelyknownView Answer on Stackoverflow
Solution 3 - Ruby on-RailsNathan CrauseView Answer on Stackoverflow
Solution 4 - Ruby on-Railssonal saveView Answer on Stackoverflow