I can't stress this enough. You should never, NEVER, come to the point where you have to change the access modifier, just to test a function.
private methods can change their signature
classes that call those private methods can change their structure
private methods come and go, there's no need for your tests to be dependent on them
The only two solutions to this problem are:
change the access modifier to public, because the behavior should be exposed outside the module (really rare case)
or just write a test for the public API that calls the private methods (almost every time the right choice)
Private methods should always be tested implicitly through the public API.
Let's say you have a User model for the following behavior
# test/models/user.rb class User def initialize(role) @role = role end def calculate_payout(hours) get_rate * hours end private def get_rate return 420 if @role == 'ceo' return 69 if @role == 'dev' return 13.37 if @role == 'janitor' end end
# Bad practice example test 'given role dev has 69 eur rate' do user = User.new('dev') expect(user['get_rate']()).to_eql 69 # DO NOT DO THIS! end
# Good practice example test 'given role ceo has 420 eur rate' do user = User.new('ceo') expect(user.calculate_payout(10)).to_eql 4200 end
That way the method
get_rate will be tested and if the method ever changes its signature, the test will still pass.
Testing private methods explicitly will make your tests brittle. Brittle tests will make your test suite meaningless and ultimately useless. Stick to the public API for testing.
Did you like this post? Make my day by sharing this post with a dev colleague!