Mark Methods Private When You Don’t Test Them

Development

Reading Time: 5 minutes

This article was originally published by Pat Shaughnessy on his blog, and with his permission, we are sharing it here for Codeship readers.

My father in law once lived in same building where Picasso was born, near the Plaza de la Merced in Málaga, Spain.


My father in law once lived in same building where Picasso
was born, near the Plaza de la Merced in Málaga, Spain.

In Ruby and many other languages, you write private methods to implement internal logic you don’t want to expose. You want the freedom to rename, repurpose, or even delete them without worrying about impacting anything else.

The private keyword signals other developers: Don’t rely on this; don’t call it; it might change. This is especially important when writing framework or library code that many other developers will use.

But which methods should you make private? Sometimes this is obvious; sometimes it isn’t. A good rule of thumb to use is: If you’re not testing a method, it should be private.

But wait a minute! Aren’t we supposed to test everything? Isn’t 100 percent code coverage the nirvana every Ruby developer seeks? Let me clarify. You should mark methods private when you test them indirectly by calling the other, public methods in the same class. Use the private keyword to help organize your code, to remind yourself what you still need to test, and what you don’t.

Three Paintings

A simple example will make this clear. Suppose I have a class that describes a painting:

Snippet_Painting

Now I can create a list of three paintings in a Minitest::Spec file like this: Snippet_MiniTest

Suppose my first requirement is to return the first painting from the list. Simple enough: Snippet_Simple enough

I just call Array#first, and I’m done. Returning the rest of the list is slightly more interesting: Snippet_interesting

Using a trick I learned from Avdi, rest always returns an array even if the input list was empty or had only one element. So far, so good. I’ve written two methods and two tests:

sdfsdf

A New Requirement

Now suppose my business requirement changes slightly, and I instead need to return the first painting sorted alphabetically by name. Once again, it’s not hard to do.

Snippet_not hard to do

And I need rest to use the same sort order, so I repeat the call to sort:

Snippet_call to sort

I’ve implemented new behavior, but still have two methods and two tests:

two-tests

Extracting a Method

Because both of my methods are covered by tests, I’m free to refactor them. I decide to extract a new method, sorted_by_name:

Snippet_sorted by name

Here I’ve simply moved the call to sort into a utility method called sorted_by_name. Now first and rest both call sorted_by_name, making the code a bit clearer and DRY-er. But now I have three methods and only two tests:

two-tests-three-methods

Sign up for a free Codeship Account

Mark Methods Private when You Don’t Test Them

Notice I didn’t bother writing a test for sorted_by_name. I know it works because my other tests still pass. The existing tests are sufficient; I am testing sorted_by_name indirectly. Because I extracted sorted_by_name from first and rest, because I refactored my code without adding any new behavior, no new tests were required.

In this scenario, take the time to mark the new, untested method as private:

Snippet_as private

The private keyword here reminds me I’ve already tested sorted_by_name, that I don’t need to write new tests for it. Now private is helping me organize my code; it’s helping me remember which methods I don’t need to test… and which methods are missing important tests.

two-tests-three-methods-private

If my tests don’t need to know about sorted_by_name, then certainly other developers don’t. It should be private. Marking it private reminds me that it is being tested indirectly, that I didn’t just forget to write a test for it. Marking it private tells other developers about what I’ve learned from my own test suite.

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.



We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.

  • Philippe Van Eerdenbrugghe

    I’ve never tackled the problem from that perspective but it’s an interesting one !
    Most of the time I’m asking myself what to test instead of what to mark private but obviously those are the two faces of the same coin.

    I really enjoyed Katrina Owen’s talk about what to test and what not to test where she covers the subject of private methods and also ingoing and outgoing methods : https://vimeo.com/68730418

    • Thanks for the video Philippe! Anybody who sees this comment –> I recommend watching it.

  • The qualm I have here is that the final tests only implicitly know about the alphabetical ordering. They have it hardcoded into the test and a future dev might not realize that it’s significant. In this case I’d prefer to see the tests using the sort method to order the test data explicitly.

    Sure this is just an example, but it’s showing the exact issue I have with relying on private to hide methods too much. I will almost always prefer public methods to private.