I am currently in a discussion with a colleague who suggests that I separate out a component that is used in my class, create an abstract interface and set the concrete instance of that component from the outside. I could use this to create a mock in the unit test so that the testability of the class is improved.
Although I understand the argument very well, I feel that the design/interface of my class is negatively affected by this.
For me, this boils down to the question: is it okay to change the class interface for the sake of testability? What is more important, the interface or the testability?
Is it okay to ask the question in such a general way, or should I present an example?
Thank you very much.
CodePudding user response:
If you are tempted to use a mock instead of the real class, then you are already designing for two interchangeable implementations: The real implementation and the test double. That's reason enough to extract out an interface.
Testability is important; a pragmatic testable unit is much more useful than a "pure" untestable unit.
Though you can label test-focused methods using names like setFooForTest
or use test documentation annotations like @VisibleForTesting
, ideally you should reflect that the test is a consumer of your interface and that your interface should be general enough for your consumer and your test. That might mean employing dependency injection or method overloads, like this:
public int doThing() {
return doThing(new DefaultCollaborator());
}
/** Does thing with a particular collaborator. Useful for testing. */
/* package */ int doThing(Collaborator collaborator) {
// ...
}