Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

why Test::More?

by fionbarr (Friar)
on Sep 10, 2013 at 13:02 UTC ( #1053252=perlquestion: print w/replies, xml ) Need Help??

fionbarr has asked for the wisdom of the Perl Monks concerning the following question:

I looked silly on a technical interview yesterday because I do not use a formal testing procedure. I have looked at Test::More/Simple and the examples looked like this:
sub hello_world { return "Hello world!"; } sub get_number { return int(rand(1000)); } ok( hello_world( ) eq "Hello world!", "My Testcase 1" ); ok( get_number( ) > 0, "My Testcase 2" );
Obviously there is more to it than this! Can someone send me a real-world example so I can see what a 'real' situation looks like?

Replies are listed 'Best First'.
Re: why Test::More?
by Your Mother (Bishop) on Sep 10, 2013 at 13:46 UTC

    Testing is really super important in a shop that is serious and trying to not waste anyone's time or accidentally ship stuff sideways to customers. Even in the shortest code or whimsical examples like yours, bugs creep in. Proper tests help ensure they don't go unnoticed.

    Perl Testing: A Developer's Notebook (ISBN 0596100922) is really quite good. Pick it up. Make your own big projects better and wow the next interview committee. Other required reading: prove, Test::Simple, Test::More, App::Prove. Plenty of other Test:: space to explore as you like.

    Here are your tests rewritten (style differences are up to you, I like to omit parens and explicit returns where possible).

    use strictures; use Test::More; # plan test count here or use done_testing($count). is hello_world(), "Hello world!", "Hello world is hello world"; # Naive test, will not catch your bug, and you have one. cmp_ok get_number(), ">", 0, "get_number() returns greater than zero"; subtest "Iterate on get_number()" => sub { my $iterations = 10_000; # Higher confidence. my $ok; for ( 1 .. $iterations ) { $ok++ if get_number() > 0; } my $msg = "get_number() returns greater than zero"; $ok == $iterations ? pass($msg) : fail($msg . " - expected $iterations > 0, got $ok"); done_testing(1); }; done_testing(3); # <- Either "plan" or delcare test count here! exit 0; sub hello_world { "Hello world!"; } sub get_number { int(rand(1000)); }
    ~>prove my-test.t -v ok 1 - Hello world is hello world ok 2 - get_number() returns greater than zero not ok 1 - get_number() returns greater than zero - expected 10000 + > 0, got 9993 1..1 not ok 3 - Iterate on get_number() 1..3 Dubious, test returned 1 (wstat 256, 0x100) Failed 1/3 subtests Test Summary Report ------------------- /home/moo/my-test.t (Wstat: 256 Tests: 3 Failed: 1) Failed test: 3 Files=1, Tests=3, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.03 cusr + 0.00 csys = 0.07 CPU) Result: FAIL

    Found your bug, right? int(rand(whatever)) can return zero. Fix with int(rand(1000)+1) and run again.

    ok 1 - Hello world is hello world ok 2 - get_number() returns greater than zero ok 1 - get_number() returns greater than zero 1..1 ok 3 - Iterate on get_number() 1..3 ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.03 cusr + 0.00 csys = 0.07 CPU) Result: PASS
      this was a super response....thanks
Re: why Test::More?
by MidLifeXis (Monsignor) on Sep 10, 2013 at 13:51 UTC

    The cases you provide are (admittedly) simplistic. When this becomes useful is when you have a method or function, and you want to document what its behavior should be

    sub frobnitz { ... } ok( frobnitz( ) eq $no_params_results ); ok( frobnitz( @some_parameters ) eq $expected_results ); ok( frobnitz( @some_other_parameters) eq $other_expected_results );

    The comparison can be any type of result that can be tested (does it throw / die, does it set some attribute on an object, etc).

    The benefit of this is that you can quickly and consistently check the same behaviors, the same way, every time, after every change, to verify that you have not broken some expected behavior. This is a huge safety net when adding a feature, refactoring, etc. Your tests are, in effect, documentation, in the form of code, that translates English requirements into something that is less prone to misinterpretation more formalized.


      thanks....opened my eyes. would you normally have a *.t file for every subroutine? How do you chain tests? (e.g. run t01.t .. t50.t)

        App::Prove is a typical harness that is used. Also see make test and build test in the build tool chain.

        I have been using (or trying to change my habits to use) Test Driven Development, to minimize the amount of untested code in my codebase. I have been using one .t file per package (well, per .pm file).*

        * - In reality, I use Test::Class with a unittests.t loader, but that is more of an implementation detail. In effect it is one test file per source file. Test::Class uses inheritance, but I think that test files could also be written using roles.


Re: why Test::More?
by choroba (Archbishop) on Sep 10, 2013 at 13:15 UTC
    Browse the t directory of any CPAN module. For example, XML::LibXML.
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      how do I find the 't' directory for a module?

        For any module on CPAN you'll find a consistent layout. Along the top, left-hand side, you'll see:

        author_link > distribution_link > module_name

        Follow the distribution link. In the top section of the page now displayed, you'll see Special Files where you'll find a link to MANIFEST (along with quite a few others).

        Follow the MANIFEST link. Now you'll see a list of links to all the files that make up the distribution. Scroll down until you find paths like t/xxxx.t. These are all the test files. You can look at the code directly from here: there's no need to download and unpack an entire distribution.

        -- Ken

        Download it from CPAN, unzip, untar it. The 't' directory does not get installed.
        Go to MetaCPAN , click links, find it :)
Re: why Test::More?
by hippo (Chancellor) on Sep 10, 2013 at 13:16 UTC

    There are thousands of real-world examples right there on CPAN. You could start with Try::Tiny if you like. I installed the newest version of it about a week ago and therefore know that it uses Test::More.

Re: why Test::More?
by McDarren (Abbot) on Sep 10, 2013 at 15:51 UTC
    I found this introduction to TDD with Perl by Grant McLean to be extremely useful.


Re: why Test::More?
by sundialsvc4 (Abbot) on Sep 10, 2013 at 18:39 UTC

    Downloading a substantial CPAN package as-described and looking at its t directory really is probably the very-best source of practical real-world testing voodoo wisdom.

    A reall-good test suite works up in stages, from low-level tests of every function of every object including exception cases, to substantially more-complex cases that build on the ones that came before.   You will be amazed at how many bugs you will find in your kitchen when you start looking systematically for them.   But, once they are gone, a test-suite can prove that they still are gone.   There is no substitute for that.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1053252]
Approved by Athanasius
Front-paged by Arunbear
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2020-02-26 06:57 GMT
Find Nodes?
    Voting Booth?
    What numbers are you going to focus on primarily in 2020?

    Results (113 votes). Check out past polls.