Unit Testing – Writing Testable Code vs Avoiding Speculative Generality

code smelldesignpolymorphismunit testing

I was reading some blog posts this morning, and stumbled across this one:

If the only class that ever implements the Customer interface is
CustomerImpl, you don't really have polymorphism and substitutability
because there is nothing in practice to substitute at runtime. It's
fake generality.

That makes sense to me, as implementing an interface adds complexity and, if there is only ever one implementation, one might argue that it adds needless complexity. Writing code that is more abstract than it needs to be is often considered to be code smell called "speculative generality" (also mentioned in the post).

But, if I'm following TDD, I can't (easily) create test doubles without that speculative generality, whether in the form of interface implementation or our other polymorphic option, making the class inheritable and its methods virtual.

So, how do we reconcile this tradeoff? Is it worth it to be speculatively general to facilitate testing/TDD? If you're using test doubles, do these count as second implementations and thus make the generality no longer speculative? Should you consider a more heavyweight mocking framework that allows mocking of concrete collaborators (e.g. Moles versus Moq in the C# world)? Or, should you test with the concrete classes and write what could be considered "integration" tests until such time as your design naturally requires polymorphism?

I'm curious to read other people's takes on this matter — thanks in advance for your opinions.

Best Answer

I went and read the blog post, and I agree with a lot of what the author said. However, if you're writing your code using interfaces for unit testing purposes, I'd say that the mock implementation of the interface is your second implementation. I'd argue that it really doesn't add much in the way of complexity to your code, especially if the trade-off of not doing so results in your classes being tightly coupled and hard to test.

Related Topic