Testing Exceptions
Sometimes things go wrong. That's okay; sometimes the best thing to do in code that detects an unrecoverable error is to pitch a fit and let higher-level code figure out what to do. If you do that, though, you need to test that behavior. As usual, there's a module to make this easy.
Test::Exception
provides the functions to test that a block of code throws (or doesn't throw) the exceptions that you expect.
How do I do that?
Suppose that you're happy with
add_positives( )
from "Testing Warnings," but your coworkers can't seem to use it correctly. They happily pass in negative
numbers
and ignore the warnings, and then blame you when their code fails to work properly. Your team lead has suggested that you strengthen the function to
hate
negative numbers ”so much so that it throws an exception if it encounters one. How can you test that?
Save the following listing as
exception.t
:
use Test::More tests => 3;
use Test::Exception;
use Error;
sub add_positives
{
my ($l, $r) = @_;
throw Error::Simple("first argument ($l) was negative") if $l < 0;
throw Error::Simple("second argument ($r) was negative") if $r < 0;
return $l + $r;
}
throws_ok { add_positives( -7, 6 ) } 'Error::Simple';
throws_ok { add_positives( 3, -9 ) } 'Error::Simple';
throws_ok { add_positives( -5, -1 ) } 'Error::Simple';
Note:
There are no commas between the first and second arguments to any of Test:: Exception's test functions
.
Run the file with
prove
:
$
prove -v exception.t
exception....1..3
ok 1 - threw Error::Simple
ok 2 - threw Error::Simple
ok 3 - threw Error::Simple
ok
All tests successful.
Files=1, Tests=3, 0 wallclock secs ( 0.03 cusr + 0.00 csys = 0.03 CPU)
What just
happened
?
The call to
throws_ok( )
ensures that
add_positives( )
throws an exception of type
Error::Simple
.
tHRows_ok( )
performs
an
isa( )
check on the exceptions it catches, so you can alternatively specify any superclass of the exception thrown. For example, because exceptions inherit from the
Error
class, you can replace all occurrences of
Error::Simple
in
exception.t
with
Error
.
What about...
|
Q:
|
How can you ensure that code doesn't throw any exceptions at all?
|
|
A:
|
Use
Test::Exception
's
lives_ok( )
function.
To ensure that
add_positives( )
does not throw an exception when given natural numbers, add an extra test to assert that
add_positives( )
throws no exceptions:
use Test::More tests =>
4
;
use Test::Exception;
use Error;
sub add_positives
{
my ($l, $r) = @_;
throw Error::Simple("first argument ($l) was negative") if $l < 0;
throw Error::Simple("second argument ($r) was negative") if $r < 0;
return $l + $r;
}
throws_ok { add_positives( -7, 6 ) } 'Error::Simple';
throws_ok { add_positives( 3, -9 ) } 'Error::Simple';
throws_ok { add_positives( -5, -1 ) } 'Error::Simple';
lives_ok { add_positives( 4, 6 ) } 'no exception here!';
If the block throws an exception,
lives_ok( )
will produce a failed test. Otherwise, the test will pass.
|
|