The Testing Anti-Patterns Drafts Vol. 1
Saturday, September 23rd, 2006“The Testing Anti-Patterns Drafts” is a collaborative effort between Stuart “Stubs are evil” Caborn and myself, which aims to identify cases of Testing gone bad.
It consists of a single document that will undergo constant enhancements and modifications, in a “pair-authoring” manner, utilizing our respective weblogs as the platform.
We hope to get input from anyone following the document, our goal being to produce an interesting resource for the TDD, or Testing Oriented in general community.
Design Pervasive Testing
Both Stuart and I consider ourselves fortunate enough to work as members of teams where TDD is practiced by default.
There are two reasons beyond the obvious as to why I find it relatively harder to code in a non TDD approach. Test Driving my code enhances my vision on how to design/model/instrument my application’s universe. Also, starting with a test means work begins and ends with coding, not meetings, discussions or modeling our vision in pictures bound to be proven unrealistic when the first coding bottlenecks arise.
Having said that, testing properly is not easy. Past the simplistic examples, proper tests are hard work, often much harder than the actual code.
Encapsulation and Behavior are two of the most important characteristics of Object Oriented design. Applying them properly is difficult, and after all the hard work, testing Classes that are very concise about their behavior and very strict about what their peers can do with them, writing meaningful, readable, fine grained tests becomes a mission.
It’s the extra effort required that sometimes phases developers who end up taking shortcuts in order to facilitate testing.
Let’s look at an example:
public void testShouldProduceComplexObject() {
ComplexObject expected = ObjectMother.getComplexObject();
ComplexObject actual = classUnderTest.getComplexObject();
assertEquals(expected, actual);
}
Obviously, such an assertion would only be valid if ComplexObject overrides the hashCode() and equals() methods. Countless times have I witnessed Classes implementing these two methods only to accommodate tests similar to the aforementioned example.
This is terminally wrong and a potential bug. Equality is an integral attribute of a Class’s behavior and should be strictly meaningful under the context of the Class’s definition.
I’m not aware of an easy way out of this sticky situation. Specific fields of the Class need to be tested for equality in isolation.
Does this mean that we need to expose all the Class fields we need to test by giving them public, or package level access? Not necessarily. In fact, not at all. After all, changing access levels would further compromise our Class’s behavior.
More and more, we have discovered Reflection to be an invaluable tool in our quest for less intrusive to purist OO design testing:
public void testShouldProduceComplexObject() {
ComplexObject expected = ObjectMother.getComplexObject();
ComplexObject actual = classUnderTest.getComplexObject();
assertEquals(getPrivateField(expected, "fieldOne"),
getPrivateField(actual, "fieldOne");
assertEquals(getPrivateField(expected, "fieldTwo"),
getPrivateField(actual, "fieldTwo");
//etc...
}
If this were a container-bean type of Class with fifteen fields, that’s a lot typing we’d have to deal with. This is not necessarily bad for a Unit Test, but we could all do with less sore fingertips.
public void testShouldProduceComplexObject() {
ComplexObject expected = ObjectMother.getComplexObject();
ComplexObject actual = classUnderTest.getComplexObject();
String[] fields = new String[] { “fieldOne”, [...], “fieldFifteen” };
for (String field : fields) {
assertEquals(getPrivateField(expected, field),
getPrivateField(actual, field);
}
}
TBC…
If you’d like to follow the discussion, feel free to grab The Testing Anti-Patterns Drafts feed.

