Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> If you test private methods: you're doing something wrong.

Maybe a silly question, but why?

If I refactor a class to pull a common piece of functionality into a private method, why would I not want a test for that?

One of the principle benefits of tests I see is allowing me to change the implementation without worrying about the behaviour, and I'm not sure why that wouldn't apply to private methods?



One reason why is because you should be testing the public behavior of a function/class not the details. The reason for this is because the public interface is what other parts of the codebase will come to rely on. Refactoring generally shouldn’t change the public interface as it will break other pieces of code within your codebase, or other codebases if it’s a library, and other systems if it’s a network api. So, if you test the public interface, generally refactors won’t break the tests.

Testing private functions also seems to be a smell that the overall setup of testing the class or function is too difficult. This can be because the class has too many branches in it, the argument list is too large, or too many other systems must be in place for it to function correctly. This, to me, indicates a public interface that is hard to use and will pass much of these issues on to the caller.

Lastly, if you are testing private functions to gain coverage then arguably the behavior in the private method isn’t actually useful to the public interface. The reason I say this is that testing the behavior of the class should end up touching all branch conditions inside the class or the public interface isn’t fully tested. By only testing the public interface it then also becomes easier to locate dead/unreachable code.

Hope that answers the why.


I would argue you absolutely need to be testing the internal details. That is the entire point of measuring branch coverage and performing mutation testing. Unit tests are not black box tests. They need to know that for special values, the unit has to follow a different code path but still produce sensible output. Reading the documentation of a function is not sufficient to determine what edge cases the unit has, but testing those edge cases is often critical to verifying that the unit adheres to its specified behavior under all conditions.

As for the smell, sometimes things are irreducibly complex. Some things in this world do require tedious book keeping. All the refactoring in the world cannot change the degrees of freedom of some problems.

Tests on consumers should not test branches of subordinate units. If you did this then the number of tests would explode exponentially with the number of branch conditions to handle all the corner cases. If a private unit produces a list of objects, but has special cases for some values of its argument, test those branches to verify it always produces the correct list. Then just make sure each caller does the correct thing with the list of objects. That is the purpose of separation of concerns: the consumer does not need to know that some values were special.


> the number of tests would explode exponentially with the number of branch conditions to handle all the corner cases

Then wouldn't you want to write something that was able to iterate through those edge-case interactions and ensure they are correct?


I'm trying to imagine what on earth your private methods can be doing that wouldn't be affected by the public interface.

There should be no situation where the same exact call in the public interface could take multiple different paths in the private method. The only thing I can think of that could make that happen would be some dependancy, which should be mocked at the top level to control these cases.


Some people call this functional testing.


Private methods are the internals of your classes. It may change a lot for performance or to make it easy to maintain, one method may become 3 or 4.

But people who use your class don't care. They input something in your public methods and expect something in return. The details of what happen inside should not matter. Adding tests there only help to slow you down and make the dev team resist needed changes. And when you add tests you increase the chances you make them useless or wrong.


Ah, I think I see. If I break the functionality by changing the implementation of a private class, that should be reflected in the public API unit tests.


That's how I see it (in Java at least), unit tests are for guaranteeing that your classes API does what it says it does.

In Python I am more loosely goosey about my unit tests and unit tests there are more for helping me write/think about tricky code.


If your private method is wrong, then your public methods will also be wrong. If your public methods are right, then it doesn't really matter what your private methods do..


I read it as using introspection/reflection to test what is essentially implementation details which are very likely to change.

This is how you write brittle tests which fail easily and cause high maintenance costs and reduced confidence in the unit-tests as a safety net.

Definitely an anti-pattern.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: