testing intermediate

How to use Test::Fatal for exception testing in Perl?

Question

How to use Test::Fatal for exception testing in Perl?

Test::Fatal is a handy Perl module designed to simplify testing code that throws exceptions (dies). It lets you easily capture exceptions during tests so you can assert whether an exception was thrown, and optionally inspect its message—all without needing complex eval blocks.

What is Test::Fatal?

Test::Fatal provides a function exception, which runs a code reference and captures any exception thrown. This helps write clean and readable tests focused on exception handling. Instead of manually wrapping code in eval blocks and checking $@, you just use exception to get the error string or undef if no exception occurred.

Basic Usage

To use Test::Fatal, you need Perl 5 installed (any modern version is fine). It is often used alongside Test::More or other testing modules.

Here’s what happens:

  • You pass a coderef (anonymous subroutine) to exception.
  • The coderef runs.
  • If it dies, exception returns the string error.
  • If no exception, it returns undef.

Common Perl Concepts:

  • coderef: an anonymous subroutine reference, e.g. sub { ... }
  • $@: variable holding the last eval error (if any).
  • die: function that throws exceptions in Perl.
  • TMTOWTDI ("There's more than one way to do it") allows exception testing via eval, Try::Tiny, or Test::Fatal.

Example: Testing Exception with Test::Fatal

use strict;
use warnings;
use Test::More tests => 3;
use Test::Fatal;

# Function to test
sub divide {
    my ($num, $den) = @_;
    die "Division by zero error!" if $den == 0;
    return $num / $den;
}

# Test 1: Normal division (no exception)
my $result = divide(10, 2);
is($result, 5, 'Divide 10 by 2 equals 5');

# Test 2: Check that division by zero throws exception
my $error = exception { divide(10, 0) };
like($error, qr/Division by zero error!/, 'Exception thrown for division by zero');

# Test 3: Check that no exception returns undef
my $no_error = exception { divide(5, 1) };
is($no_error, undef, 'No exception for valid division');

Explanation

1. We define a divide function which dies on division by zero.

2. The first test uses normal call and compares the result.

3. The second test uses exception to capture the die message from division by zero. We then confirm the error matches the expected regex.

4. The third test confirms no exception means exception returns undef.

Version Notes and Gotchas

  • Test::Fatal is core in Perl distributions from around 5.10, but availability might vary; you can install it from CPAN if needed.
  • Use exception only for code references; don't call the tested function directly because you want exception to run and catch any exceptions.
  • Be careful of context (scalar vs list): exception always returns a scalar (the exception string or undef).
  • Combining Test::Fatal with other test modules like Test::More allows more expressive tests.

In summary, Test::Fatal offers a clean and efficient way to write exception tests in Perl, saving you from manual eval handling and making tests simpler and more readable.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 69ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
1..3
ok 1 - Divide 10 by 2 equals 5
ok 2 - Exception thrown for division by zero
ok 3 - No exception for valid division
STDERR
(empty)

Was this helpful?

Related Questions