Ashley Sheridan​.co.uk

Testing Exception Not Thrown With PHPUnit

Posted on

Tags:

Testing exceptions in PHPUnit is fairly easy, and you can be as specific as you need with testing the details of the exceptions being thrown.

But what if you need to test that an exception wasn't thrown?

The Exception Problem

There are many clean code advocates who will tell you that testing for exceptions not being thrown is a sign that your code is doing something wrong, and that the code should be refactored so that a test for the negative is not needed.

One of the main arguments against using exceptions for controlling the flow of the application is that they effectively become nothing more than fancy GOTO statements, which can make code harder to read.

That doesn't mean we should avoid usign exceptions altogether in our efforts to write clean code, but perhaps we could write code in a way that we wouldn't be stuck with this testing problem at all.

Sometimes however when writing tests, we don't always have the luxury to alter existing code, so we might be left with no choice but to try and test around an exception not being thrown.

Valid Exception Usage

So what might be a valid use-case that we would still need to test? There are typically 2 cases where exceptions should be used:

  1. A situation occuring in a part of the program where there's not enough context to continue, such as a failed database insert. Passing control back up the chain to a level that can handle this is the best option.
  2. A serious error where the alternative to a thrown exception might be damage to data, like attempting to insert data at a specific point in a file that had been updated between the application locating that insert point and writing new data (bad file locking).

Testing the Negative

The way to test this is fairly simple:

public function testTheThing { // set up test-specific stuff here try { $classInstance->methodUnderTest(); $this->assertTrue(true); } catch (\Exception $exception) { $this->fail("Exception thrown testing thing"); } }

If the exception is thrown, your PHPUnit test fails, ultimately warning you that some of your methods logic has a failure. You might be wondering why there's a need for the extra assertTrue(true) here. I used this to ensure that when the test passes, there's still at least one valid assertion within it, as PHPUnit may display "risky test" warnings on the console if a test contains no assertions depending on your test configuration.