EP 23 - Test-specific subclasses and self-shunted tests

77 views
Skip to first unread message

Michel Henrich

unread,
Dec 26, 2013, 10:49:23 AM12/26/13
to clean-code...@googlegroups.com
<with Danny's voice> Uncle Bob? </with Danny's voice>

I've just finished watching episode 23 on mocking, and I was quite surprised when you presented the test-specific subclassing and self-shun patterns. And by surprised, I mean confused.
I've been working with TDD for a rather short period (two years), and I ended up using those techniques without a second thought - they came naturally; and since, at first, I didn't quite see the tests as more important than the production code, I thought it was OK to use them. 
However, as I was watching the episodes on TDD, I begun to see these techniques as anti-patterns, especially when you were teaching how to create dummies, stubs and spies in separate, dedicated classes for testing, naming them properly, and so on. This appealed to me, especially since it was a clear example of how to apply the SOLID principles and to write clean tests. So imagine my surprise when the techniques which I was slowly convinced of being bloated and hacked shortcuts, were presented as actual testing patterns. Though from the episode, I was not able to tell whether you presented these patterns just for clarity's sake, or if you recommend their use.

TL;DR: I believe that Test-Specific Subclassing and Self-shunted tests are anti-patterns, and so should be avoided. In my experience, the tests become hard to read, hard to maintain (too tightly coupled to the implementation in case of subclassing) and eventually fragile... leading to code rot!

I know there isn't much of a question here, I'd just like to start this discussion to see other opinions on the use of these techniques.

Jon Reid

unread,
Dec 29, 2013, 5:00:35 PM12/29/13
to clean-code...@googlegroups.com
I wouldn't say they're anti-patterns. They're tools, and usually there are better tools. But for folks who are just getting started in their TDD journey, these are simpler to grasp. They break the "But how???" barrier, especially for legacy code (and folks used to writing in a legacy style). Because they're simple, using them is quicker than reworking your dependencies.

The trick is NOT TO STOP THERE. In "The Art of Unit Testing, 2nd edition" Roy Osherove writes about Extract and Override:

"That makes [Extract and Override] quick and clean to perform… I like to call this method 'ex-crack and override' because it's such a hard habit to let go of once you know it."

And in his Object Mentor article on self-shunt, Michael Feathers writes:

"‘Self’-shunt is a nice way to start a class when you need collaborators immediately, but often it is just a stepping-stone. ‘Self’-shunting test cases can become unwieldy, as they get larger. At that point, normal refactoring rules apply. …You can factor out a Mock Object…"

In other words, don't stop there. (One of the things I deeply enjoy about TDD & Clean Code is that the more I learn, the more I feel like a beginner again. And I've been at this for a dozen years!)

Uncle Bob

unread,
Dec 31, 2013, 10:15:14 AM12/31/13
to clean-code...@googlegroups.com
I think it's an overstatement to call these techniques "anti-patterns".  Indeed the very term "Anti-pattern" is a misrepresentation of what a pattern is.  

[[Warning:  Pedantic Rant]]

A pattern is a named solution to a problem in a context, that has been successfully tried many times.  A pattern is neither pure good nor pure bad.  It's just something that has been tried a few times, been found to work, and been given a name.  As such, there are good uses for a pattern, and bad uses for the same pattern.

A so-called anti-pattern is something that has been tried many times and found not to work.  Anti patterns are pure bad.  There are no good uses for them.  

Do you see the asymmetry?  Patterns are sometimes useful.  Antipatterns are never useful.  So antipatterns are not the opposite of patterns.  

[[End of Pedantic Rant]]

The testing patterns presented in E23 are sometimes useful; so they are indeed patterns.  It's not true that they are never useful, so they are clearly not anti-patterns.  

However, you (and Jon) are correct in that a usage of one of these patterns is most likely a stepping stone to a different pattern.  As the project grows in complexity, you will likely refactor a self-shunt, or a test-specific subclass into a true mock.  

[[Warning: Another Pedantic Rant]]

I learned Jiu Jitsu in the school of the 8th Light.  There were three classes of techniques:  Shodan (first), Nidan (second), and Sandan (third).  You mastered the techniques in that order.  A black belt was someone who had mastered all three techniques.

Each technique was more "powerful" than the previous.  Shodan was an impressive way to take down an opponent.  Nidan was more difficult to master, and to apply, but once learned was a much more effective than shodan,   Sandan was like a miracle.  It was very difficult to master, and tiny errors in position could render it ineffective.  But when you did it right --  well, it was amazingly effective.

Upon learning Nidan, students would eschew shodan because nidan was so much more powerful.  And Nidan students stood in awe of the Sandan masters. 

Upon learning Sandan, students would eschew both shodan and nidan, because it was just so cool to get Sandan right, and take down your opponent with one hand without leaving your chair.  

The cure for this attitude was to get into a match with the Sen Sai, who would thwart every one of your advanced Nidan and Sandan moves, and win the match, with nothing but simple Shodan techniques. 

[[End of second Pedantic Rant]]

Moral of the story:  Respect the simple techniques for their simplicity. 
Reply all
Reply to author
Forward
0 new messages