7

Sometimes private functions of a module or class are simply yet-to-be-extracted internal units of functionality, which might deserve their own tests. So why not test them? We will write tests for them later on if/when they're extracted. So why not write the tests now, when they're still part of the same file?

To demonstrate:

enter image description here

First, I wrote module_a. Now I want to write tests for it. I would like to test the 'private' function _private_func. I don't understand why I wouldn't write a test for it, if later I might refactor it to its own internal module anyway, and then write tests for it.


Suppose I have a module with the following functions (it could be also be a class):

def public_func(a):
    b = _do_stuff(a)
    return _do_more_stuff(b)

_do_stuff and _do_more_stuff are 'private' functions of the module.

I understand the idea that we should only test the public interface, not the implementation details. However, here's the thing:

_do_stuff and _do_more_stuff contain the majority of the functionality of the module. Each one of them could be a public function of a different, 'internal' module. But they are not yet evolved and large enough to be extracted to separate files.

So testing these functions feels right because they are important units of functionality. If they were in different modules as public functions, we would have tested them. So why not test them when they're not yet (or ever) extracted to a different file?

15
  • 2
    Possible duplicate of New to TDD. Should I avoid private methods now?
    – gnat
    Nov 9, 2016 at 14:59
  • 2
    "Private methods are beneficial to unit testing..." "...sticking with private method brings me a useful, reliable enhancement in unit tests. In contrast, weakening access limitations "for testability" only gives me an obscure, hard to understand piece of test code, which is additionally at permanent risk of being broken by any minor refactoring; frankly what I get looks suspiciously like technical debt"
    – gnat
    Nov 9, 2016 at 15:00
  • 3
    "Should I test private functions?" No. Never, ever, ever.
    – David Arno
    Nov 9, 2016 at 15:08
  • 2
    @DavidArno Why? What's the alternative to testing internals? Only integration tests? Or making more things public? (though in my experience I mostly test public methods on internal classes, not private methods) Nov 9, 2016 at 15:13
  • 1
    If it's important enough that there is a need to write tests for it, then it should already be in a separate module. If it's not, then you test its behaviour by using the public API. Nov 9, 2016 at 17:58

4 Answers 4

13

The need to test is not the same as the need to be public.

Non trivial code needs testing regardless of exposure. Non public behavior doesn't need to exist let alone be tested.

These conflicting views can lead you to want to make every function public or refuse to factor out code into a function unless it will be public.

This is not the answer. Be willing to create private helper functions. Test them through the public interface that uses it as much as possible.

If testing through the public interface doesn't exercise the private function sufficiently the private function is trying to allow too much.

Validation can help narrow what the private function allows. If you can't pass a null going through the public interface you can still throw an exception if one comes through anyway.

Why should you? Why test what you'll never see? Because things change. It may be private now but be public later. The calling code could change. Code that explicitly rejects null makes proper usage and expected state clear.

Of course null could be fine. It's just an example here. But if you expect something, it's useful make that expectation clear.

That might not be the kind of testing you had in mind but hopefully you'll be willing to create private helper functions when appropriate.

The desire to test is good but it shouldn't be the driving force in the design of your public API. Design the public API to be easy to use. It likely won't be if every function is public. The API should be something people can understand how to use without diving into the code. Don't leave such people wondering what this weird helper function is for.

Hiding public helper functions in an internal module is an attempt to respect the need for a clean API while exposing helpers for testing. I won't say this is wrong. You might be taking the first step towards a different architectural layer. But please, master the art of testing private helper functions through the public functions that use them first. That way you won't over use this workaround.

4
  • I've come up with an approach, I'd like to hear your opinion: whenever I'm in a situation where I want to test a private function, I'll check if I can test it sufficiently through one of the public functions (including all edge cases, etc). If I can, I will not write a test for this function specifically, but only test it through testing the public functions which use it. However if I feel the function can't be tested sufficiently through the public interface and does deserve a test of its own, I will extract it to an internal module where its public, and write tests for it. What do you think?
    – Aviv Cohn
    Nov 11, 2016 at 16:22
  • I'll say I'm asking the same thing the other guys who replied here :) I'd like to hear everybody's opinion.
    – Aviv Cohn
    Nov 11, 2016 at 16:25
  • Again, I won't tell you no. I am concerned that you've said nothing about keeping an eye on how that impacts usability. The difference between public and private isn't structural. It's usage. If the difference between public and private is a front door and a back door then your work around is to build a shed in the back yard. Fine. So long as people don't get lost back there. Nov 11, 2016 at 19:00
  • 1
    Upvoted for "If testing through the public interface doesn't exercise the private function sufficiently the private function is trying to allow to much."
    – Kris Welsh
    Nov 14, 2016 at 18:34
8

Short answer: No

Longer answer: Yes, but via the public 'API' of your class

The whole idea of private members of a class is that they represent functionality that should be invisible outside the 'unit' of code, however big you want to define that unit to be. In object oriented code that unit often ends up being a class.

You should have your class designed such that it is possible to invoke all the private functionality through various combinations of input state. If you find there isnt a relatively straight forward way to do this, its probably hint that your design needs closer attention.


After clarification of the question, this is just a matter of semantics. If the code in question can operate as a separate standalone unit, and is being tested as if it were public code, i cant see any benefit of not moving it into a standalone module. At present, it only serves to confuse future developers (including yourself, in 6 months time), as to why the apparently public code is hidden inside another module.

3
  • Hi, thanks for your answer :) Please reread the question, I have edited to clarify.
    – Aviv Cohn
    Nov 9, 2016 at 15:27
  • I've come up with an approach, I'd like to hear your opinion: whenever I'm in a situation where I want to test a private function, I'll check if I can test it sufficiently through one of the public functions (including all edge cases, etc). If I can, I will not write a test for this function specifically, but only test it through testing the public functions which use it. However if I feel the function can't be tested sufficiently through the public interface and does deserve a test of its own, I will extract it to an internal module where its public, and write tests for it. What do you think?
    – Aviv Cohn
    Nov 11, 2016 at 16:25
  • I'll say I'm asking the same thing the other guys who replied here :) I'd like to hear everybody's opinion.
    – Aviv Cohn
    Nov 11, 2016 at 16:26
5

The whole point of private functions is that they are hidden implementation details that can be changed at will, without changing the public API. For your example code:

def public_func(a):
    b = _do_stuff(a)
    return _do_more_stuff(b)

If you have a series of tests that only use public_func, then if you rewrite it to:

def public_func(a):
    b = _do_all_the_new_stuff(a)
    return _do_all_the_old_stuff(b)

then, as long as the the return result for a particular value of a remains the same, then all your tests will be good. If the return result changes, a test will fail, highlighting the fact that something broke.

This is all a good thing: static public API; well encapsulated inner workings; and robust tests.

However, if you'd written tests for _do_stuff or _do_more_stuff and then made the above change, you'd now have a bunch of broken tests, not because the functionality changed, but because the implementation of that functionality changed. Those tests would need rewriting to work with the new functions, but having got them working, all you'd know is that those tests worked with the new functions. You'd have lost the original tests and so would not know if the behaviour of public_func had changed and so you tests would basically be useless.

This is a bad thing: a changing API; exposed inner workings tightly coupled to tests; and brittle tests that change as soon as changes to the implementation are made.

So no, do not test private functions. Ever.

16
  • Hello David, thanks for your answer. Please reread my question, I have edited to clarify.
    – Aviv Cohn
    Nov 9, 2016 at 15:24
  • 1
    Meh. There's nothing wrong with testing internal functions. I personally don't write a non-trivial function of any kind unless I can cover it with a couple of unit tests, so banning testing on internal functions would pretty much preclude me from writing internal functions, robbing me of a very useful technique. API's can and do change; when they do, you must change the tests. Refactoring an inner function (and its test) doesn't break the outer function's tests; that's the whole point of having those tests. Bad advice overall. Nov 9, 2016 at 15:29
  • What you're really arguing is that you shouldn't have private functions. Nov 9, 2016 at 15:30
  • 1
    @AvivCohn They're either big enough to warrant testing, in which case they're big enough to get their own file; or they're small enough that you don't need to test them separately. So which is it?
    – Doval
    Nov 9, 2016 at 16:12
  • 3
    @RobertHarvey No, it makes the argument "break down big classes into loosely-coupled components if necessary". If they're really not public that's probably a good use-case for package-private visibility.
    – Doval
    Nov 9, 2016 at 16:30
0

Ask yourself why a function is tested. You test it because you want to know if there are problems in that function, and to have confidence there are none. Now some people think this is only relevant when calling a function written by someone else and made public. That’s nonsense. If you develop some module and write a function that you need in your implementation then you want to test it. For the exact same reasons as someone else’s public function.

If someone disagrees, just take the function and turn it into its own module where it is public.

Some languages explicitly support this by allowing you to mark functions as “testable”, meaning they can be called from unit tests but are otherwise private.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.