CROSP
CROSP

Reputation: 4617

Unit test for testing Perl script/module exceptions and dieing

I am trying to create unit tests for my script using the Test::More and Test::Exception libraries.
I have read these articles How to test for exceptions in Perl and Test::Exception.
The first article describes exactly what I need, to test my subroutine for throwing exception or dieing.
But I cannot get it working. Consider some examples

    #!/usr/bin/env perl
    package My::SuperModule;
    use strict;
    use warnings;
    use Net::Ping;
    use Utils::Variables::Validator;

    sub new
    {
        die "Hello";
        #Getting class name from, stored in $_[0]
        my $class = shift;
        #Getting user name from arguments $_[1]
        my $user_name = shift;
    ........
}

And my test file

    use warnings;    # this warns you of bad practices
    use strict;      # this prevents silly errors
    use Test::More; # for the is() and isnt() functions
    use Test::Exception;
    do './My/SuperModule.pm';
    #Testing module loading 
    print "=================Testing module loading=================\n";
    use_ok ( 'My::SuperModule' );
    use_ok ( 'My::SuperModule', 'new' );
    #Testing module subroutines
    dies_ok { My::SuperModule->new() } "Died in class constructor";
     sub div {
    my ( $a, $b ) = @_;
    return $a / $b;
};
    dies_ok { div( 1, 0 ) } 'divide by zero detected';

It stops executing script in any case, but I need just to handle if died, I need to test this because I manually invoke die if data is invalid or something other , but it dies and doesn't continue to execute the script further. Giving me a message

Uncaught exception from user code:
    Hello at ../libs/My/SuperModule.pm line 31.
    My::SuperModule::new('My::SuperModule', '') called at SuperModule.t line 24
# Tests were run but no plan was declared and done_testing() was not seen.
# Looks like your test exited with 2 just after 8.

But if to use division by zero it works like I want

ok 16 - divide by zero detected

So it fails but doesn't terminate execution of the script.

I am newbie in Perl, so cannot solve the problem by myself, maybe there is not problem at all, just no way to do what I want.
Please suggest what to do or say where is my fault here.

EDIT

I have just tried to divide by zero inside my module new subroutine and here is the message I got.

Illegal division by zero at ../libs/My/SuperModule.pm line 33 (#1)
    (F) You tried to divide a number by 0.  Either something was wrong in
    your logic, or you need to put a conditional in to guard against
    meaningless input.

I really cannot figure out what is going on. Please help with this.

Upvotes: 3

Views: 1042

Answers (2)

Sinan Ünür
Sinan Ünür

Reputation: 118128

Here is a minimal example that works:

package My::SuperModule;
use strict;
use warnings;

sub new {
    die "Hello";
}

package main;

run() unless caller;

use Test::More;
use Test::Exception;

sub run {
    dies_ok { My::SuperModule->new } "dies ok";
    done_testing;
}

Output:

C:\...\t> prove -v my.pl
my.pl ..
ok 1 - dies ok
1..1
ok
All tests successful.
Files=1, Tests=1,  0 wallclock secs ( 0.09 usr +  0.00 sys =  0.09 CPU)
Result: PASS

Note that, for the purpose of providing a self-contained example, I combined the module code and the test script into a single file.

Also note that I did not clutter the test script with unnecessary print statements.

If you want, you can use diag to show some output:

diag "Checking if Test::Exception::dies_ok will catch die in new";
dies_ok { My::SuperModule->new } "dies ok";
done_testing;

Output:

C:\...\t> prove my.pl
my.pl .. # Checking if Test::Exception::dies_ok will catch die in new
my.pl .. ok
All tests successful.
Files=1, Tests=1,  0 wallclock secs ( 0.05 usr +  0.02 sys =  0.06 CPU)
Result: PASS

As opposed to plain print statements, diag output will actually be shown when tests are run from a harness such as prove.

Upvotes: 4

Dave Cross
Dave Cross

Reputation: 69244

It works for me. All I needed to do was:

  1. Comment out the two modules that the test wasn't using (Net::Ping and Utils::Variables::Validator - I don't have them installed).
  2. Add 1; as the last line of the module - so it returns a true value.
  3. Remove the extra require and use_ok from the test.
  4. Added done_testing; to the end of the test - so the test harness knows that it got to the end of the tests.

You probably don't care about the first item on that list, but if you fix the others, it should work for you.

Upvotes: 3

Related Questions