Only Test Through Public Interfaces
Tags: unittests, tdd, testing, softwaredesign
Published: 2020-07-01 11:29:59

One of the most commonly asked questions in developer communities regarding Test-Driven Development and unit testing is whether one should write unit tests for private methods, and if so, how to accomplish this. The answer to this question is quite simply:

> “Of course. As many lines of code as possible should be covered by unit tests”.

However, the way we accomplish this is very important.

The behaviour of a class or module should only be tested through its public members. So if we’ve followed the steps of “Red, Green, Refactor”, every line of code that is used by the public methods of a class or module has been exercised. Whenever a private method is not directly or indirectly used by these public methods, then it’s probably no longer needed. A private method that is not being used can therefore be removed. There’s no need to keep dead code around. It only confuses other developers of the team later on. Besides, that’s why we make use of version control systems.

![Testing private methods through their public counterparts](https://dev-to-uploads.s3.amazonaws.com/i/8v2fh1izkg0l7e90y7n6.png)

When we only test through public methods, we also guarantee to exercise the code of the private methods that are being used. Private methods should be considered as an implementation detail. So there is no reason to directly try to put them under test.

However, there might be some cases where we just want to write unit tests for a private method. The first and best approach is to simply turn this private method into a public method instead. If this bothers us, we have to question ourselves why that is. This usually means that our class or module has too many responsibilities and that we should refactor this particular part of the code anyway. One way might be to move the private method in question as a public method of a new class.

![Moving a private method as a public method to new class](https://dev-to-uploads.s3.amazonaws.com/i/odnip3z5ju8bktwwy6ni.png)

A good design implies that the code is easy to test. When it’s not easy to test, then the design of the system is not that very good to begin with. This is why some developers refer to the expression [“listening to the tests”](https://principal-it.eu/2018/11/listening-to-the-vital-signs-of-tdd/). Unit tests very quickly amplify when something is not right with the design of the system.

Some programming languages or platforms enable developers to use reflection, or some kind of meta-programming, in order to reach and execute private methods at runtime. I would strongly advice against using such techniques for unit tests.

Nonetheless, this might come in handy when refactoring a very nasty, legacy code base. In that case, we can sparingly use such an approach to enable us to make some progress in our refactoring endeavours. However, we don’t want to keep these kinds of tests around for very long. Unit tests that employ reflection or meta-programming are too tightly coupled to the implementation of the Subject Under Test. At some point, we want to end up with a nice and clean public interface that is easy to test and for which implementation can be easily changed as well. So make sure to remove unit tests that make use of reflection or meta-programming as soon as possible.