Preliminary notes
I'll not go into the distinction of the different kinds of test there are, there are alreadyalready a few questionsquestions on these sites regarding that.
I'll take what's there and that says: unit testing in the sense of "testing the smallest isolatable unit of an application" from which this question actually derives
The isolation problem
What is the smallest isolatable unit of a program. Well, as I see it, it (highly?) depends on what language you are coding in.
Micheal Feathers talks about the concept of a seam: [WEwLC, p31]
A seam is a place where you can alter behavior in your program without editing in that place.
And without going into the details, I understand a seam -- in the context of unit testing -- to be a place in a program where your "test" can interface with your "unit".
Examples
Unit test -- especially in C++ -- require from the code under test to add more seams that would be strictly called for for a given problem.
Example:
- Adding a virtual interface where non-virtual implementation would have been sufficient
- Splitting -- generalizing(?) -- a (smallish) class further "just" to facilitate adding a test.
- Splitting a single-executable project into seemingly "independent" libs, "just" to facilitate compiling them independently for the tests.
The question
I'll try a few versions that hopefully ask about the same point:
- Is the way that Unit Tests require one to structure an application's code "only" beneficial for the unit tests or is it actually beneficial to the applications structure.
- Is the code generalization that is needed to make it unit-testable useful for anything but the unit tests?
- Does adding unit tests force one to generalize unnecessarily?
- Is the shape unit tests force on code "always" also a good shape for the code in general as seen from the problem domain?
I remember a rule of thumb that said don't generalize until you need to / until there's a second place that uses the code. With Unit Tests, there's always a second place that uses the code -- namely the unit test. So is this reason enough to generalize?