Search code examples
perlunit-testingexceptionperl-moduledie

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.


Solution

  • 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.