Improving the tests with try-finally block

This week I have learned a neat trick that you can apply to your test cases. You are testing an edge case. The system under test is expected to throw an exception. But, after the exception, you need to do a few assertions. Usually, I did it this way:

/**
 * @dataProvider markAsUndeliverableFailDataProvider
 */
public function testMarkAsUndeliverableFail(Order $order): void
{
    $exception = null;

    try {
        $order->markAsUndeliverable();
    } catch (\Throwable $exception) {
    }

    self::assertInstanceOf(OrderStatusChangeFailed::class, $exception);
    self::assertTrue($order->isAlreadySentToProduction());
}

But, there is a better way to do it! Check out the much more readable version with try-finally:

/**
 * @dataProvider markAsUndeliverableFailDataProvider
 */
public function testMarkAsUndeliverableFail(Order $order): void
{
    $this->expectException(OrderStatusChangeFailed::class);

    try {
        $order->markAsUndeliverable();
    } finally {
        self::assertTrue($order->isAlreadySentToProduction());
    }
}

Viola! Look how clean this is 🔥