logo
Free, unlimited AI code reviews that run on commit
git-lrc git-lrc GitHub Install Now We'd appreciate a star git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

Test::Warnings - Test for warnings and the lack of them

Author

       Karen Etheridge <ether@cpan.org>

Caveats

       If you are using another module that sets its own warning handler (for example Devel::Confess or
       diagnostics) your results may be mixed, as those handlers will interfere with this module's ability to
       properly detect and capture warnings in their original form.

Contributors

       •   Graham Knop <haarg@haarg.org>

       •   Tina Müller <cpan2@tinita.de>

       •   A. Sinan Unur <nanis@cpan.org>

       •   Leon Timmermans <fawaka@gmail.com>

Description

       If you've ever tried to use Test::NoWarnings to confirm there are no warnings generated by your tests,
       combined with the convenience of "done_testing" to not have to declare a test count, you'll have
       discovered that these two features do not play well together, as the test count will be calculated before
       the warnings test is run, resulting in a TAP error. (See "examples/test_nowarnings.pl" in this
       distribution for a demonstration.)

       This module is intended to be used as a drop-in replacement for Test::NoWarnings: it also adds an extra
       test, but runs this test before "done_testing" calculates the test count, rather than after.  It does
       this by hooking into "done_testing" as well as via an "END" block.  You can declare a plan, or not, and
       things will still Just Work.

       It is actually equivalent to:

           use Test::NoWarnings 1.04 ':early';

       as warnings are still printed normally as they occur.  You are safe, and enthusiastically encouraged, to
       perform a global search-replace of the above with "use Test::Warnings;" whether or not your tests have a
       plan.

       It can also be used as a replacement for Test::Warn, if you wish to test the content of expected
       warnings; read on to find out how.

Functions

       The following functions are available for import (not included by default; you can also get all of them
       by importing the tag ":all"):

   allow_warnings([bool])-EXPERIMENTAL-MAYBEREMOVED
       When passed a true value, or no value at all, subsequent warnings will not result in a test failure; when
       passed a false value, subsequent warnings will result in a test failure.  Initial value is "false".

       When warnings are allowed, any warnings will instead be emitted via Test::Builder::note.

   "allowing_warnings"-EXPERIMENTAL-MAYBEREMOVED
       Returns whether we are currently allowing warnings (set by "allow_warnings" as described above).

   "had_no_warnings(<optionaltestname>)"
       Tests whether there have been any warnings so far, not preceded by an "allowing_warnings" call.  It is
       run automatically at the end of all tests, but can also be called manually at any time, as often as
       desired.

   "warnings({code})"
       Given a code block, runs the block and returns a list of all the (not previously allowed via
       "allow_warnings") warnings issued within.  This lets you test for the presence of warnings that you not
       only would allow, but must be issued.  Testing functions are not provided; given the strings returned,
       you can test these yourself using your favourite testing functions, such as Test::More::is or
       Test::Deep::cmp_deeply.

       You can use this construct as a replacement for Test::Warn::warnings_are:

           is_deeply(
               [ warnings { ... } ],
               [
                   'warning message 1',
                   'warning message 2',
               ],
               'got expected warnings',
           );

       or, to replace Test::Warn::warnings_like:

           cmp_deeply(
               [ warnings { ... } ],
               bag(    # ordering of messages doesn't matter
                   re(qr/warning message 1/),
                   re(qr/warning message 2/),
               ),
               'got expected warnings (in any order)',
           );

       Warnings generated by this code block are NOT propagated further. However, since they are returned from
       this function with their filename and line numbers intact, you can re-issue them yourself immediately
       after calling warnings(...), if desired.

       Note that "use Test::Warnings 'warnings'" will give you a "warnings" subroutine in your namespace (most
       likely "main", if you're writing a test), so you (or things you load) can't subsequently do
       "warnings->import" -- it will result in the error: "Not enough arguments for Test::Warnings::warnings at
       ..., near "warnings->import"".  To work around this, either use the fully-qualified form
       ("Test::warnings") or make your calls to the "warnings" package first.

   "warning({code})"
       Same as "warnings( { code } )", except a scalar is always returned - the single warning produced, if
       there was one, or an arrayref otherwise -- which can be more convenient to use than warnings() if you are
       expecting exactly one warning.

       However, you are advised to capture the result from warning() into a temp variable so you can dump its
       value if it doesn't contain what you expect.  e.g. with this test:

           like(
               warning { foo() },
               qr/^this is a warning/,
               'got a warning from foo()',
           );

       if you get two warnings (or none) back instead of one, you'll get an arrayref, which will result in an
       unhelpful test failure message like:

           #   Failed test 'got a warning from foo()'
           #   at t/mytest.t line 10.
           #                   'ARRAY(0xdeadbeef)'
           #     doesn't match '(?^:^this is a warning)'

       So instead, change your test to:

           my $warning = warning { foo() };
           like(
               $warning,
               qr/^this is a warning/,
               'got a warning from foo()',
           ) or diag 'got warning(s): ', explain($warning);

   allow_patterns
         allow_patterns(qr/always allow this warning/);
         {
           my $temp = allow_patterns(qr/only allow in this scope/, qr/another temporary warning/);
           ... stuff ...
         }

       Given one or more regular expressions, in "qr/.../" form, add them to the allow-list (warnings will be
       emitted with "note" rather than triggering the warning handler). If the return value is saved in a local
       variable, the warning exemption will only be in effect for that local scope (the addition is reversed at
       the end of the scope); otherwise, the effect is global.

   disallow_patterns
       Given one or more regular expressions, in "qr/.../" form, remove it from the allow-list. The pattern must
       exactly match a pattern previously provided to "allow_patterns".

Import Options

":all"
       Imports all functions listed above

   ":no_end_test"
       Disables the addition of a "had_no_warnings" test via "END" or "done_testing"

   ":fail_on_warning"
       When used, fail immediately when an unexempted warning is generated (as opposed to waiting until
       "had_no_warnings" or "done_testing" is called).

       I recommend you only turn this option on when debugging a test, to see where a surprise warning is coming
       from, and rely on the end-of-tests check otherwise.

   ":report_warnings"
       When used, had_no_warnings() will print all the unexempted warning content, in case it had been
       suppressed earlier by other captures (such as "stderr_like" in Test::Output or "capture" in
       Capture::Tiny).

Name

       Test::Warnings - Test for warnings and the lack of them

Other Options

       You can temporarily turn off the failure behaviour of this module, swapping it out for reporting (see
       ":report_warnings" above) with:

         $ENV{PERL_TEST_WARNINGS_ONLY_REPORT_WARNINGS} = 1;

       This can be useful for working around problematic modules that have warnings in newer Perl versions.

See Also

       •   Test::NoWarnings

       •   Test::FailWarnings

       •   blogs.perl.org:           YANWT           (Yet          Another          No-Warnings          Tester)
           <http://blogs.perl.org/users/ether/2013/03/yanwt-yet-another-no-warnings-tester.html>

       •   strictures - which makes all warnings fatal in tests, hence lessening the need  for  special  warning
           testing

       •   Test::Warn

       •   Test::Fatal

Support

       Bugs may be submitted through the RT bug tracker <https://rt.cpan.org/Public/Dist/Display.html?Name=Test-
       Warnings> (or bug-Test-Warnings@rt.cpan.org <mailto:bug-Test-Warnings@rt.cpan.org>).

       There    is    also    a    mailing    list    available    for    users   of   this   distribution,   at
       <http://lists.perl.org/list/perl-qa.html>.

       There is also an irc channel available for users of  this  distribution,  at  "#perl"  on  "irc.perl.org"
       <irc://irc.perl.org/#perl-qa>.

       I am also usually active on irc, as 'ether' at "irc.perl.org" and "irc.libera.chat".

Synopsis

           use Test::More;
           use Test::Warnings;

           pass('yay!');
           done_testing;

       emits TAP:

           ok 1 - yay!
           ok 2 - no (unexpected) warnings (via done_testing)
           1..2

       and:

           use Test::More tests => 3;
           use Test::Warnings 0.005 ':all';

           pass('yay!');
           like(warning { warn "oh noes!" }, qr/^oh noes/, 'we warned');

       emits TAP:

           ok 1 - yay!
           ok 2 - we warned
           ok 3 - no (unexpected) warnings (via END block)
           1..3

To Do (Or: Possible Features Coming In Future Releases)

       •   allow_warnings(qr/.../) - allow some warnings and not others

       •   more  sophisticated  handling in subtests - if we save some state on the Test::Builder object itself,
           we can allow warnings in a subtest and then the state will revert when the subtest ends, as  well  as
           check for warnings at the end of every subtest via "done_testing".

       •   sugar for making failures TODO when testing outside an author environment

Version

       version 0.038

See Also