In an earlier post I did describe a possibly better way of handling fixture tear down in JUnit.
In this post I look at the way assertions work. JUnit is actually widely used as a driver for all kinds of tests, not only unit tests. I think this is perfectly reasonable as it leverages all the support that JUnit has in IDEs and build tools.
However one problem is that a test case will be aborted on the first failed assertion. It would be nice, if you could specify, whether the failure should abort the test or just be recorded as a failure, thereby enabling better feedback on potentially longer running tests.
While this is probably generally agreed for integration/ acceptance tests I recently found that it would also be nice to have “non failing asserts” for unit tests. Let’s consider the following two unit tests for a copy constructor:
@Test public void copyConstructorPopulatesCenter(){ Circle circle = new Circle(new Point2D.Double(10,10), 2); Circle clone = new Circle(circle); assertEquals(new Point2D.Double(10,10), clone.getCenter()); } @Test public void copyConstructorPopulatesRadius(){ Circle circle = new Circle(new Point2D.Double(10,10), 2); Circle clone = new Circle(circle); assertEquals(2, clone.getRadius(), 0.001); }
While we are testing two separate things, all the setup code actually hides what the copy constructor is about, so I’d prefer to write something along these lines:
@Test public void clonePopulatesFields(){ Circle circle = new Circle(new Point2D.Double(10,10), 2); Circle clone = new Circle(circle); assertEquals(new Point2D.Double(10,10), clone.getCenter()); assertEquals(2, clone.getRadius(), 0.001); }
This is much terser. The zealots will cry that there shall be only one assert per test. My thinking is, that that’s all true, but then this method contains two tests. The only (albeit not big) problem is, that when the center
is not populated properly it’s preventing the second test from being executed. Another interesting observation is that having multiple “tests” in one method saves us from naming them, which in itself is a bit of an issue.
I am not sure if such a feature can be implemented by just writing a custom JUnit runner. The beautiful simplicity of the JUnit approach stems from the fact, that it uses exceptions to report failures. Thereby allowing the test code not to carry around some kind of test context. However once you have got a test context other things become possible, which I hope to elaborate on in a later post.
Leave a Reply