I'm hitting a bit of a quandary with response to testing: I'm losing some faith in unit testing, or at least busywork unit testing relative to integration testing.
At issue is the way Tapestry is constructed; there's a lot of small moving parts that work together (integrate together might give you some foreshadowing). Sometimes testing the small pieces won't accomplish much. Case in point:
public class SecureWorker implements ComponentClassTransformWorker
{
public void transform(ClassTransformation transformation, MutableComponentModel model)
{
Secure secure = transformation.getAnnotation(Secure.class);
if (secure != null)
model.setMeta(TapestryConstants.SECURE_PAGE, "true");
}
}
This piece of code looks for the @Secure annotation on a component class, and records a bit of meta data that will be used elsewhere.
In the past I've written a chunk of tests even for something as simple as snippet; Following that pattern, I'd write two tests: 1) what if the annotation is missing? 2) what if the annotation is present? I'd use mock objects to ensure that the correct methods of the correct dependencies are invoked in each scenario. However, to write those tests, even leveraging existing base classes to manage the mock objects I'd need, would require several times as much test code as the production code I want to test.
But what would that prove? This bit of code will be useless without a large number of other pieces yet to be written: code that uses that meta data and forces the use of secure HTTPS links and so forth. Code that integrates this worker into the chain of command for processing component classes. Code that verifies that requests for pages that are marked as secure are, in fact, secure.
In other words, to verify the behavior I need to validate that all of those pieces are working together, that they are all integrated.
That doesn't mean I'm calling for the abandonment of unit tests. What I'm saying is that pointless unit tests don't accomplish much. I've found that unit tests are invaluable for testing edge cases and error conditions. Even the most rabid test driven pundits don't expect you to unit test your accessor methods ... I think tiny classes like this SecureWorker fall under the same general umbrella. I intend to focus my efforts on the integration tests that will encompass this code in concert with other code. And maybe write a few unit tests along the way, as long as they actually have value.
Update: It's not that I can't write the test, it's that doing so is not always worth the effort. Here's a similar test I wrote in the past:
public class SupportsInformalParametersWorkerTest extends InternalBaseTestCase
{
@Test
public void annotation_present()
{
ClassTransformation ct = mockClassTransformation();
MutableComponentModel model = mockMutableComponentModel();
SupportsInformalParameters annotation = newMock(SupportsInformalParameters.class);
train_getAnnotation(ct, SupportsInformalParameters.class, annotation);
model.enableSupportsInformalParameters();
replay();
new SupportsInformalParametersWorker().transform(ct, model);
verify();
}
@Test
public void annotation_missing()
{
ClassTransformation ct = mockClassTransformation();
MutableComponentModel model = mockMutableComponentModel();
train_getAnnotation(ct, SupportsInformalParameters.class, null);
replay();
new SupportsInformalParametersWorker().transform(ct, model);
verify();
}
}
Great: this detects whether @SupportsInformalParameters is on the class ... but I have other integration tests that actually stress the behavior when the annotation is present and when the annotation is absent. Ultimately, that tests both of these cases, and the code that ensures that this code is even executed, and the desired behavior of the component (with and without the annotation). Failures are unlikely to occur in this code, but likely in other code. What is the value of this test? Not even code coverage, and the integration tests hit both cases already.