Trying to Test a Private Method is a Signal That You Need Another Class

Sometimes I find myself wanting to write tests (or stubs) for a private method. It recently occurred to me that I should consider that impulse an indicator that there is another object hiding in my code. If the private method is sufficiently complicated that it requires direct testing, then the class is probably doing too much.

That code should be extracted to a new object that can be tested in isolation.

Imagine customer class that performs a credit check before possibly offering a loan.

customer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Customer
def should_offer_loan?
credit_score >= passing_credit_score
end
private
def credit_score
# Complicated stuff with a web service and database
# ...
end
def passing_credit_score
500
end
end

Trying to test the credit score method directly is an anti-pattern. We could just make it public, but doing that only exposes an implementation detail. In this domain, clients of the Customer class don’t need to know the customer’s credit score: its only used to determine if the customer is eligible for the loan.

Extracting a CreditCheck class gives another object that can be tested directly and in isolation. Its also now far easier to stub out the web-service and database calls to allow faster tests.

Before reaching for a stub, or making a method needlessly public, consider if there is another object hiding out and waiting to be given a life of its own.