How to spec a private method
Ruby on-RailsRspecRuby 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)