http://blog.magicaltux.net/2009/09/19/striving-for-a-better-...
http://blog.magicaltux.net/2009/09/19/striving-for-a-better-...
Incidentally, this is why "test first" is more than just a methodology for selling high-priced consultants. At least it lets you see your tests fail and then pass, rather than just pass. Lots of common patterns pass in the presence of incorrect code.
An example that a coworker was complaining to me about recently:
void testFooBarException() {
try {
thisShouldThrowFooBarException()
} catch (FooBarException ignored) {}
}
Can you spot the bug? The test still passes even if thisShouldThrowFooBarException doesn't throw an exception. Oops.I personally avoid this by checking that I can make the test fail when I expect it to fail, by editing some values or commenting something out. But that doesn't scale, that only saves you once.
Something to think about.
void testFooBarException() {
try {
thisShouldThrowFooBarException()
fail() // Should have thrown exception
} catch (FooBarException ignored) {}
}
If you're feeling super fancy, you can even do some asserts in the catch block to make sure the FooBarException has an expected exception message. assertRaises(FooBarException, thisShouldThrowFooBarException)
Impossible to mistype, and states exactly what should happen. @Test(expected = FooBarException.class)
void testFooBarException() {
thisShouldThrowFooBarException()
} /**
* Tests that thisShouldThrowFooBarException throws FooBarException
*
* @expectedException FooBarException
*/
public function testFooBarException() {
thisShouldThrowFooBarException();
}
but I much prefer /**
* Tests that thisShouldThrowFooBarException throws FooBarException
*/
public function testFooBarException() {
$this->setExpectedException('FooBarException');
thisShouldThrowFooBarException();
}
Much more explicit and you're less likely to miss it when trying to grok someone else's unittest. @Test(expectedExceptions = FooBarException.class)
public void test() {
thisShouldThrow();
}
If the method doesn't throw or throws the wrong kind of exception, this test will fail. @Test(expectedExceptions = FooException.class)
public void test() {
firstDoThis();
thenThat();
thenSomeMore();
thisShouldThrow();
}
Now you're only asserting that any of these statements throw, anywhere in the code under test. That's significantly weaker and I've seen it mask real problems in code.I think using plain try something/fail/catch is clearer, or using Closures and an assertThrows if your language supports it.
shouldn't you be automating that? :-D
Whenever I do this, I feel awful, because:
> But that doesn't scale, that only saves you once
You need to fuzz test your tests. (I always forget the name of the awesome Java tool for this....) If you can randomly mutate your test code (negate boolean conditional, etc) and your tests still pass, they fail.
EDIT: NIH is pretty bad overall, but it's especially terrible in crypto, where 'useless' and 'useful' take on something akin to binary values, rather than a continuum.