I'm relatively new to Go but I come from a C#/OOP background where unit testing private methods isn't something that's generally done. I currently have a senior developer telling me it's "bad design" if private package methods can't be tested. Is this generally true of Go?
-
You will need to get some clarification about what your senior developer means. Private methods, by their very nature, cannot have unit tests written for them directly, because they are private. You can test logic in the private methods by writing tests for the public methods that call the private methods. – Greg Burghardt Nov 17 '23 at 15:59
-
1There are many similar questions on this site. So many it is difficult to find only one duplicate. – Greg Burghardt Nov 18 '23 at 17:38
4 Answers
This has almost nothing to do with the specific programming language.
Thorough testing requires that you exercise all the behaviour that your code might have to perform in production. (This can mean covering not only all the lines of your code base, but also all the circumstances in which they run; this is why good coverage tools expect four different outcomes from an if
with a conjunction as is condition and not just two.)
Private helper functions are supposed to be called from public methods and therefore should also receive coverage during the tests of those methods, but it's a lot more effort to coax higher-level functions to thoroughly exercise the helpers, and much of this effort involves repetitive and pointless higher-level manipulations.
Much better to make the helper functions accessible at least to the testing suite, test them thoroughly and then ignore them when writing tests for other functions. It is almost always worth making them public (sometimes putting them into a utility class) just to achieve that.
(There is a philosophical misunderstanding among many programmers that "this function isn't supposed to be called by business code directly, so it would be misleading to make it public". This is misunderstanding the role of different parts of your code base. Testing code is a first-class citizen even though it is not shipped to the customer, and if it needs access to do its job, then the method isn't as private as you thought.)

- 109,273
-
Objective C and Swift have an annotation at testable. private at testable functions are treated as public while compiling unit tests, and private otherwise. So no risk to expose them by accident. (Site doesn’t like at characters in comments, it thought I tried talking to someone named testable) – gnasher729 Nov 17 '23 at 13:23
-
Four outcomes for a conjunction? Only if there is no short-circuiting going on, otherwise it's three. The point stands though. – Deduplicator Nov 17 '23 at 16:10
Why mark a method as public?
If it's so it can be tested you're designing an API for testers. Not to be used. If it's public it can be accessed from all sorts of places and has to provide all those places with what they expect. Ensuring that is a lot of work.
Why mark a method as private?
If it's so you don't have to test it you're just being lazy. Being private means you don't have to look far to see how it's used. It makes analysis easy. Don't give that up easily.
How much testing is enough?
A private method should service some public method. If you can't fully exercise the private method from the public one then the private one is allowing too much. It's OK to reject negative numbers because the public method never passes them. You don't have to force negative numbers into the private method just to watch it throw an otherwise unreachable exception. Exercising defensive coding is a poor excuse to blow up your accessibility.
When to switch?
However, popular private methods suffer from the same problem that public methods do. Their wide use means they serve many masters. This is when it's worth promoting them to public. Not because they need testing and this is the only way. But because they need their expectations locked down in one place.
If you're wondering how a private method becomes popular you haven't seen the 1,000+ line monsters I have. Count yourself lucky.
If a private method is making some public methods pass their tests and some others fail then what exactly is the fix?
Understand, just because a method is marked public doesn't mean it's intended for consumption outside. Sometimes an object abstracts away a whole bunch of other objects (see façade pattern). But remember, that kind of encapsulation isn't free. Setting that up is work.
I remain convinced that testing is not a good argument to change a method's accessibility. However, if you have multiple tests of multiple public methods exercising a private method you may benefit from admitting this thing's life isn't so private any more. Making it public allows you to lay down the law on the behavior expected from this thing. But now you have to deal with it being public.

- 1,323

- 108,538
As I see, unit test verifies a functional unit, which include the private methods.
While, to elaborate, a functional unit may look like this:
func addAB(a, b int) int {
return a + b;
}
A unit test should verify the functional unit (i.e. the function) works correctly, it returns a+b
rather than a*b
or sth else.
Private or not, all the same, as I understand.

- 1
-
1
-
To tell the truth, I don't think the simple answer need extra elaboration. Less is better, as I always believe. – giskard Nov 17 '23 at 10:27
There is a philosophical difference.
One position is that I write a module, expose public functions for others to call which is the reason why the module exists in the first place, and these public functions are tested by others using unit tests. Anything else is my problem.
The other position is that while I write that module I write methods to make my module work. Nobody but me cares about these methods or even knows about them, BUT I DO. So I want to test them, using unit tests obviously, and I want them to be private.
So these methods, only one developer cares that they work correctly. But that is true for many methods, which are public but only used by one caller. (Not all methods, some are used everywhere). And that one developer wants unit tests, rightfully so.

- 44,814
- 4
- 64
- 126
-
2This answer seems to advocate that public functions need not be tested, since other modules will do that work for you, but I don't think that's the intent – Jacob Raihle Nov 17 '23 at 14:39