I have a feeling too many people get it wrong so let me stress:
@Test(expected = SomeException.class) // IS BAD FOR YOU
I do enjoy jUnit a lot, thanks guys for sharing! Yet, I don’t like @Test(expected) feature of jUnit. In my TDD classes I simply teach to avoid using it. I admit the feature can potentially make few tests cleaner. However, it tends to bring more trouble than value. Newbies too often misuse it which leads to poor quality tests. Therefore:
Rule 1: don’t use @Test(expected)
My colleague (cheers Bartek!) pursues Master at the Uni. They teach him testing. One day a lecturer was presenting some test code:
@Test(expected=Exception.class) public void testSomething() { //line 1: throws NullPointerException //lines 2-30: some crappy test code }
The test is useless. Due to some bug in the setup the test method breaks in line 1. Therefore most of the test code is not even executed. The expected exception does great job in hiding this issue; the test is green! Therefore:
Rule 2: If you violate Rule #1 then at least make the exception very specific. Example:
@Test(expected=BreadOutOfStockException.class) public void shouldBuyBread() {}
Even if you use specific exception then the test does not document exactly where the exception is thrown. Sometimes it may lead to subtle bugs. Therefore:
Rule 3: Don’t violate Rule #1 when the test method has multiple lines.
Instead you can simply write:
@Test public void shouldBuyBread() throws Exception { //given me.goToBakery(bakery); bakery.setBreadAmount(0); try { //when me.buyBread(); //then fail(); } catch (BreadOutOfStockException e) {} }
Above is my preferred way of documenting ‘exceptional’ behavior. There you go, it is The Ultimate Test Template for ‘exceptional’ behavior.
JUnit is getting better. New goodies for exception handling in tests arrive. @Rule ExpectedException better documents what action triggers the exception. Also, it nicely maps to //given //when //then style. The downside is that you need some extra code if you want to interrogate the exception, for example if you want assert if exception message contains a substring (api as of 07-2010). Nevertheless:
Rule 4: Favor @Rule ExpectedException over @Test(expected) when test method has multiple lines.
Rule 5: Keep an eye on new versions of your testing libraries.
If you are already at RI in TDD than consider my Rule #1 as a safety net. You’ll never know when a new junior team member joins. He may easily misuse the patterns he sees in the codebase. Javadoc for JUnit does not say how to safely use @Test(expected) (at the moment).
If you are learning testing don’t get too upset with my dogmatic rules. If only you write any tests then I am smiling already. You smile too, write tests and be happy. Soon you’ll get your RI rank in TDD.
Rule 6: Write tests & smile!