Skip to content
Dec 1 / Lasse Koskela

Test Everything, but not Private Methods

Stumbling onto Ron Jeffries’ blog about testing everything but not accessors I was reminded of a question I get asked surprisingly often – how can I test private methods in [programming language]? When somebody pops this question I always say, you shouldn’t test private methods. And you shouldn’t.

The conversation then typically continues with a “But…” and I end up elaborating on why I say that. This time I’ll elaborate in the Internet, which hopefully helps spread this thought.

“I want to test a private method”

The fundamental motivation for wanting to test private methods is fear. We fear that our code coverage report’s 100% result isn’t the whole truth (and it isn’t) and we don’t trust our unit tests – the ones that already test the private method indirectly – to have kept out all critters from that piece of code encapsulated behind the magic keyword private.

Why don’t we trust our tests? First of all, in most of the cases when this question is popped the code hasn’t been written test-first. Tests that are written afterward tend to suffer from confirmation bias – we write them to prove to ourselves that we are indeed the great programming geniuses who never make a mistake. Such tests can indeed be much less than a full-cover insurance.

The code is also to blame for our lack of trust. We rationalize our need to write direct tests for a private method by pointing out how hideously long, complex and ugly that method is. This line of thinking exhibits itself quite clearly when people respond to my strict statement with, “…but you just said that we should test ‘everything that could possibly break’ and this private method here looks so ugly that it could break at any time!”

“I understand. And you should not test that method if it’s private.”

In this phase of the dialogue we’ve typically establish one thing: the person asking the question really wants to test that private method, usually for the reasons mentioned above. And that is perfectly reasonable. Yet, I persist and restate that they should not write tests for that private method. So what am I thinking? Why shouldn’t we test it directly?

For one, writing tests for a private method might not be technically possible in your chosen programming language without obnoxious trickery like invoking a private method through Java’s Reflection API. Such tests are also bound to break when you swoosh ahead with those lightning-fast refactorings your IDE vendor has graciously automated for you – because referring to methods and classes through literal strings makes the IDE blind to that link, effectively cutting your tests off from the reach of the Rename Method refactoring you just pulled off in Eclipse.

Second, private methods are details that you clearly don’t want to expose through the class’s public API. After all, if you’d be OK with making that private method public then you wouldn’t have asked the question in the first place. Package private and protected methods are a bit of a gray area in this regard. Bumping up the private method’s visibility so that the tests can invoke it but not so much as to make it part of the public API kind of solves the problem of resorting to ugly hacks – you can now invoke the method without reflection. However, the artery is still exposed and your class’s internals are leaking on the floor. Your tests are testing the object’s implementation, not its intended behavior.

“So what would you do?”

At this point we’ve usually established that the method in question is covered indirectly by other tests but that it’s so complex or important that you want to test it directly. So what would I do?

I would test it as a public method on another class.

The whole pain of seeing that private method, wondering whether it truly works or not, and struggling to decide whether to leave it like it is, whether to increase its visibility and test it directly, or whether to resort to the mortal sin of reflection – all of this pain is trying to tell us something. The code is trying to tell us something.

Clearly that piece of code is important and essential enough that it should get a new home and become a public method on some other class – quite possibly on a whole new class. Writing direct tests for it over there would not be an issue anymore.

A place for everything and everything in its place. It seems that Mr. Franklin was a programmer himself.

14 Comments

  1. Lance Walton / Dec 1 2010

    I concur.

    Extract Class / Extract Method Object / Extract Something and make it public. Then keep extracting until that complex method is replaced by something so simple that people ask why you bothered to write tests for it.

  2. Smoo / Dec 2 2010

    What nonsense.

    Typical, inane, valueless, TDD nonsense.

    “The fundamental motivation for wanting to test private methods is fear.” Boldly stated. And wrong. (And is the fundamental motivation for wanting to write a public method, fear, too?)

    The fundamental motivation for wanting to test private methods is the same as for wanting to test any method:

    i) You want to gain some confidence that your method works (albeit with a subset of values that it might possibly take; testing never proves that a method works, just that it works for some values).

    ii) You want be alerted to unintended refactoring consequences, should you happen to make any, later on.

    Your solution – making private methods public – weakens encapsulation, making many more methods available to receive dependencies by unwary programmers and degenerating your system into a mess.

    You’re an idiot.

    You do not understand programming.

    I pity you.

    • Lasse Koskela / Dec 2 2010

      “Smoo”,

      I feel like I’ve upset you with my blog and I’m sorry for that. I also struggle with your suggestion that I’m an idiot and don’t understand programming. Obviously we disagree on that count.

      Putting that aside, I would like to understand your reasoning better. Specifically, I don’t see how your two fundamental motivations for wanting to test private methods is not fear? Sure, fear is a stronger word than being uncomfortably uncertain whether the code works but the essence is the same – you’re not sure if the private method is written correctly and you’d like to be more certain that it is.

      As far as my suggestion about making that private method public elsewhere weakening encapsulation, I sense that we’re not speaking about the same thing. Encapsulation isn’t a technical matter of keeping things private. After all, even the private stuff you can get to using reflection etc. Encapsulation is a matter of object-oriented design and what I suggest is that not every single class in your code base need to be part of the public API – that there can be classes and objects that are only used internally, classes that aren’t part of your domain model.

      If you’re worried about your fellow programmers degenerating your system into a mess, why are you working with them? Sounds like an awful place to be – and that you have a lot more important issues to attend to than whether you split a class into two.

      Besides, how is it better that those unwary programmers stuff the degenerative dependencies into one monolithic class? If they’re that unwary wouldn’t they put them somewhere anyway? If they’re not quite that unwary then wouldn’t it be easier for them to notice that the apple doesn’t belong with the oranges if, instead of a 20-line method about all kinds of fruit, they’re about to stuff that apple into a 4-line method that only talks about oranges?

  3. Philip Schwarz / Dec 2 2010

    Good post…

    here is what Rainsberger says in ‘JUnit Recipes – Practical Methods for Programmer Testing’:

    As you begin testing behaviour, rather than methods, your design will tend to show certain characteristics. In particular, there will be a public method for each operation, representing an “entry point” for exercising the behaviour. For a collection, these operations include add() and remove(). Behind this public method there may be non-public methods that the former invokes to help do its work. For a collection, these “helpers” may include resizing a dynamically sized collection when the underlying data structure runs out of space. This is part of the add() behaviour but not necessarily a method you expect the outside word to invoke. Typically you extract blocks of code and place them in private methods. There will come a time during the testing of a complex bit of behaviour that you will want to test one of those private methods on its own. If you want to write a test for that private method, the design may be telling you that the method does something more interesting than merely helping out the rest of the class’s public interface. Whatever that helper method does, it is complex enough to warrant its own test, so perhaps what you really have is a method that belongs to another class – a collaborator of the first. If you extract the smaller class from the larger one, the helper method you want to test becomes part of the newly extracted class’s public interface, so it is now “out in the open” and visible to the test you are trying to write. Moreover, by applying this refactoring, you have taken a class that had (at least) two independent responsibilities and split it into two classes, each with its own responsibility. This supports the Single Responsibility Principle of OO programming, as Bob Martin describes it.

  4. Philip Schwarz / Dec 2 2010

    And here is Feathers in “Working Effectively with Legacy Code”:

    “This question comes up over and over again from people new to unit testing: “How do I test private methods?”. Many people spend a lot of time trying to figure out how to get around this problem, but [...] the real answer is that if you have the urge to test a private method, the method shouldn’t be private; if making the method public bothers you, chances are, it is because it is part of a separate responsibility: it should be on another class.”

  5. Philip Schwarz / Dec 3 2010

    James Shore wrote the following: Testing Private Methods http://jamesshore.com/Blog/Testing-Private-Methods.html

  6. Jon / Dec 5 2010

    Sorry, but there are better ways to solve this problem, neatly captured in this post from the JUnit list:

    http://tech.groups.yahoo.com/group/junit/message/23108

    I also don’t understand the premise: if I want to test a public method, it’s “good” but if I want to test a private method, it’s “fear”? This makes no sense.

    • Lasse Koskela / Dec 5 2010

      Jon,

      I didn’t actually say that wanting to test a public method wouldn’t be fear. If the public method is equally horrid as the private method that makes you want to write direct tests for it then yes, I’d say that fear is likely your dominant motivation for writing that test – or some other less strong word like “worry”.

      That wasn’t my point, however. My point is that the right way to address this situation is to factor out the class that’s hiding inside the private method, not to work around its private-ness.

      The “better ways to solve this problem” described in Cedric’s post you linked to – making the private method package protected (package private) and adding a for-testing-only comment – are in my books just workarounds to a design problem. Useful tricks to be aware of but alike to deodorant when what you really need is a shower.

    • Philip Schwarz / Dec 9 2010

      @Jon

      Do you find Lasse’s usage of the word ‘fear’ less objectionable when you consider the many precedents set by various Luminaries of automated unit testing and test-driven development?

      E.g. Kent Beck in Test Driven Development by Example: “What don’t you have to test? The simple answer, supplied by Phlip is, ‘Write tests until fear is transformed into boredom.”

      E.g. J.B.Rainsberger in JUnit Recipes – Practical Methods for Programmer Testing: “There may be no complete way to classify methods as being too simple to break. We have provided a couple of reasonable heuristics in this essay, and if you participate in the JUnit mailing lists, you will occasionally see this topic discussed—often in gory detail. We recommend that you test until fear turns to boredom: if you think it might break, then test it until your thinking changes.”

  7. David Brady / Dec 5 2010

    Lasse, thank you for writing this. I started to politely disagree here but it became such a long-winded ramble that I moved it to my own blog. I especially appreciate you addressing the concern (which I do indeed have) that methods that can break should be tested.

    I’ve started making the case that “extract private method to public class” is not a cure-all, leaving for later the actual proposition of what private code looks like when it should be tested and yet left private. I invite your comments here: http://www.heartmindcode.com/blog/2010/12/yes-you-should-test-private-methods-sometimes/

    Thank you again, this was well-thought-out and written.

    • Lasse Koskela / Dec 5 2010

      David,

      I agree that extracting the private method to a public class is not a cure-all. I just can’t remember a situation where it wouldn’t have been an improvement over the status quo. I’m looking forward to reading your future blogs about alternative solutions.

Trackbacks and Pingbacks

  1. Tweets that mention Test Everything, but not Private Methods | Lasse Koskela -- Topsy.com
  2. Heart, Mind and Code » Blog Archive » Yes You Should Test Private Methods (Sometimes)

Comments are closed.