Bad Practice: Setting Expected Exceptions in Unit Tests
2011-09-04I was in a talk at the Kansas City Developers Conference about unit testing patterns, and it something came up in the conversation that was new to me, so I figured I'd share. Unit testing frameworks are, at their core, large try/catch blocks. Errors or unmet assertions are converted into framework-specific exceptions, and then caught. The test runner then marks those exception-throwing tests as failed/skipped/etc...
This has been updated! Read this as well.
Sometimes tests need to check for exceptions though, so most frameworks have methods to do that. In PHPUnit there are three ways to check for an exception.
- Use the
@expectedException
annotation - This is a specifically formatted comment in the docblock of the test method that tells the test runner to require the listed exception or the test will fail. - Use the
setExpectedException()
method - This tells the test runner to check for a specific exception, but it is more explicit about the timing of the exception, because an exception that is thrown before the method call will result in a test error (not a failure), resulting in more information to the user. - Use a try/catch block. This is the best method because it is the most explicit about looking for the exception exactly where you expect it to be thrown. Anything else is (and should be) an error. You can see an example of this method in the PHPUnit docs.
The basic idea here is that the most specific test is best, because you have the least likelihood of a false negative or a test error slipping through the cracks. Happy testing.