5

We are developing a new API at work. My colleague and I are having different opinion regarding whether internal classes should be unit tested or not.

Points given by my colleague for not unit testing internal classes

  1. The unit tests should be written against public classes/methods only
  2. You should be able to cover your complete code, including the internal classes via the public API itself. If your internal classes are not being tested via the public interface, that means there are some missing test cases, or you found a dead code which is not needed.
  3. Writing unit tests for internal classes might result in redundant testing or might force to write code which is never needed.

Points given by me in favor of unit testing internal classes

  1. Covering complete code through unit testing only public classes might be difficult/impractical. Writing unit tests for internal classes ensures that they behave correctly in their own world at least and we can have integration tests to test the correctness of whole application.
  2. Even if there are some redundant unit tests, it is better than having missing test cases at the top level.
  3. Internal classes are public to it's surroundings so we should test them independently. If there is only 1 public class and 100 internal classes, it is very difficult to cover all the scenarios via the public interface.

I tried searching online but seems like there is no best practise or standard opinion about this. What do you think is a good approach to follow?

Note to java people: "internal " is a keyword in C# which limits the visibility of the class to the assembly. The class won't be accessible outside the package/assembly. It is not equivalent to private class.

Samarsh
  • 565
  • 5
  • 18
  • While it is true that comprehensive unit testing against public classes and methods should be enough, the reality is that unit tests are rarely going to be fully comprehensive. In fact, by the Halting Problem, you can't guarantee that your unit tests are comprehensive. Unit testing against internal classes and methods provides you additional confidence that you have caught potential problems. – Robert Columbia Jul 13 '16 at 15:21
  • 1
    Too broad/too opinion based for SO. Some form of this question is likely already answered/discussed on [programmers.se]. – Alexei Levenkov Jul 13 '16 at 15:22
  • @AlexeiLevenkov Didn't know SO is not for opinion based questions. Can this be moved to programmers? Btw, I didn't find any discussion around this exact topic. – Samarsh Jul 13 '16 at 15:27
  • I don't think it will fit programmers in current format either, but check out they [tour](http://programmers.stackexchange.com/tour) and [help](http://programmers.stackexchange.com/help) as you should have already done for SO. Than ask question there if you can edit your one to fit they rules. – Alexei Levenkov Jul 13 '16 at 15:42
  • (There is already plenty of opinions expressed in http://stackoverflow.com/questions/5601730/should-private-protected-methods-be-under-unit-test?rq=1 which can easily be considered duplicate of this... - note that presence of existing question on SO does not necessary mean it is on-topic) – Alexei Levenkov Jul 13 '16 at 15:44
  • 1
    Voting to reopen, because this question can be answered based on facts (although opinion-based answers are also possible). – Sergey Kalinichenko Jul 13 '16 at 16:16
  • Side note: when you are doing TDD, you write unit tests for each and any piece of production code that you create; and going one step further: if you do TDD "as meant to be"; you only create production code by *refactoring*. So in other words: upfront, you might not even know which classes will stay internal, and which will contain methods that you later on want to "expose" to the outside world. In that sense - you simply test everything. Of course ... one could decide later on, to delete some of those test - to only keep those that give you "good return on investment". – GhostCat Jul 14 '16 at 07:11
  • Regarding the deletion of tests and "ROI" ... you might want to listen to http://www.se-radio.net/2016/05/se-radio-episode-256-jay-fields-on-working-effectively-with-unit-tests/ – GhostCat Jul 14 '16 at 07:11
  • @Jägermeister, If you will write unit test only for public methods/classes of you library then all internal/private units will be tested through them. Not testing internal units give a possibilities to freely refactoring internal logic while public units still passed their unit tests. In TDD you must start working only from public methods and while refactoring you create some "helper" methods – Fabio Jul 16 '16 at 18:25

1 Answers1

8

This should be decided case-by-case:

  • You should unit test internal classes that provide shared functionality - some classes in your library provide a place for shared code. Although they will be tested indirectly through classes using them, an additional direct testing lets you distinguish between problems with the class itself vs. problems with class usage.
  • You should not unit test internal classes that could be privately nested - some classes provide implementation logic for a single class, or a single class hierarchy. Such classes could be converted to a nested class, but kept as top-level classes for aesthetic or philosophical reasons. These classes need to be tested through public interfaces of the class that uses them.

Unit testing shared implementations comes especially helpful when you need to refactor shared code. If you make a breaking change, and all your unit tests are done indirectly through other classes, you end up with multiple unit test failures, none of which points to the root cause. If, on the other hand, you have direct unit tests for the shared implementation, the root cause is much easier to detect.

In addition, you would not lose the coverage of code of the internal class by refactoring tests of classes that use it, because you have direct tests of the class itself.

Your arguments apply to classes of from the first bullet point (shared implementation), while your colleague's arguments apply to classes from the second bullet point (private implementation).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523