SubclassToTest is an
AntiPattern:
AntiPattern Name:
SubclassToTest
Type:
Design
Problem: Need to fake, mock or stub methods in a
ClassUnderTest, and/or classes it uses.
Context: automated (xUnit) testing of one or more classes in a system
Forces: [forces]
Supposed Solution:
- Subclass the ClassUnderTest.
- Override method(s) that need to be faked/mocked/stubbed, for testing purposes.
- Extract object creation methods for classes that this class creates that also need to be tested or mocked.
- Override these creation methods, creating fake/mock/stub subclasses, to override their methods.
- Repeat for however many layers of classes needed.
Resulting Context:
- No class used in the test is directly, fully, completely a ClassUnderTest.
- It's difficult to succinctly describe or reason about the various methods being overridden, for each test.
- It becomes more and more difficult to refactor production code, because any method not static, private or final, may have been overridden in one or more tests.
- Seductive forces: why this is so popular:
- It's quick easy and simple.
- Why, despite the seductiveness, this is actually a BadThing:
- Complexity grows rapidly and unpredictably.
- Reuse of test code is difficult.
- Refactoring of production code becomes more and more difficult.
Replacement positive patterns:
Design Rationale: [rationale]
Related AntiPatterns:
Applicable Positive Patterns:
AntiPatternCategory:
DevelopmentAntiPattern / lack of
ArchitectureAntiPattern
Also Known As: [other names]
Examples in the Literature:
Examples in Practice:
[Discussion]
"Discussion"?? Here's a quarter, sonny. Go get yourself a language with DynamicTyping!
Doesn't seem like
DynamicTyping would avoid the problem; rather, it might make it worse, by making it more difficult to see the tests that are overriding
ClassUnderTest methods.
In my opinion,
SubclassToTest is a bad idea. First, I think having a
UnitTest that needs to muck around in the implementation details of a class points to an encapsulation problem or maybe some problem with the abstraction. Second,
SubclassToTest inhibits one's ability to refactor. However, if I restrict
UnitTesting to public features, I am free to refactor the implementation and view the class from the
using perspective.
Therefore, I always write
UnitTests without violating the interface of the
ClassUnderTest. After all, if you can't reach some behavior from the
PublicInterface, why is it even in the class?
As a result of doing this, I get to see my class from the perspective of class
user rather than class
provider. If
I end up feeling the desire to violate the abstraction, so will the
real user.
Therefore, when you feel the desire to go beyond you public features, instead take the opportunity to revisit the design of your class interface.
FWIW, I
do have a parallel package hierarchy (as described above) so my tests can access package-data without having to be shipped with the production code. This way, you don't pollute the package namespace. I use JBuilder, so I just change my source path from "project\src" to "project\src;project\test". All my
TestCases go into the "project\test" directory but look as if they are all one project to the IDE. However, I rarely, if ever have actually used this feature to access package visible attributes -- it's more just a convenient way to organize my test cases. { This is also the way Maven organizes the sources by default. }
[Additional comment moved to AbstractTest.]
--
RobertDiFalco
"The
SubclassToTest AntiPattern should be banned." --
JeffGrigg
See also:
SubclassToTestDiscussion
CategoryAntiPattern