FAQ

On 1/11/16 4:53 PM, Chad Granum wrote:
Test::More/Test::Builder work VERY hard to ensure nothing inside them alters $! or $@. This is for
thing like this:

ok(do_something_scary());
is($!, 0, "expected $! val");
is($@, undef, '$@ not changed');

Without Test::More/Builder being careful to support this, the second 2 assertions could fail because
something inside ok() modifies $! or $@.
If your test functions modify the really common parts of your global environment then it becomes
very difficult to test them... and testing error reporting is a very common thing you'd want to do!

Kent already pointed out why changing this makes testing $! and $@ very, very awkward. Let's see
that again.

     my ( $error, $exception );
     ok(do {
               local $@;
               local $!;
               my $ret = do_something_scary());
               ( $error, $exception ) = ($!, $@);
               $ret
     });
     is($error, 0, "expected $! val");
     is($exception, undef, '$@ not changed);

Gross. I don't know how many times I've written code like this. I hate it. I always encapsulate
it somehow. And when a library doesn't have good global discipline it makes it even harder for me
to have good global discipline.

We tell the users that $! and $@ are only safe per function call. Then we encourage them all over
the docs and interface to pass function return values directly into test functions. Then we tell
them they should be testing their error cases... but to do safely requires gross scaffolding.
That's not fair to the user. The result will be that people won't test their error conditions,
library quality will drop, and you'll waste a lot of time on a bug that should have been tested.

The argument that $! is only reliable per function call, that's a lowest common denominator
thinking. One of the fundamental design principles of Test::Builder was that it had to be the
GREATEST common denominator!

I don't write libraries to the lowest common denominator. I write libraries that raise the bar and
encourage others to do so as well. Perl 5's error handling is bad, but that doesn't mean my
library's error handling also has to be bad. As library authors we've been spending decades working
around Perl 5's bad parts. We know how to do it better. This is extraordinarily important for a
language's testing library: if you can't test it (or it's gross and annoying) then it won't happen.
  If you want to see better global discipline in Perl libraries, then the testing library has to
start first, because everything will use it.

Test libraries are first and foremost about the user. They encourage the user to more and better
testing! Implementation effort is a much, much lesser concern. And all the positives reasons below
not to do it are implementation reasons. There are no positives for the Test2 user.
*Reasons for dropping this promise from Test2:*

* Simplifies code
* $! and $@ are altered by many many things, adding { local ... } around all of them is a pain
* Sometimes internals you don't expect to set $! will
* Perl itself documents that you cannot depend on $! and $@ being unchanged past the immediate
line after you set it.
* Test::Builder will continue to protect $! and $@, so nothing will break
* Test2 is new, nothing depends on it preserving these
The one below is the only reason that talks about making Test2 better for the user.
*Reasons not to drop it:*

* It is helpful to people who might not realize $! and $@ are often altered unexpectedly.

I am asking for input in case I missed any reasons/arguments for either side. In either case
backwards compatibility will be preserved.

-Chad

Search Discussions

Discussion Posts

Previous

Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 10 of 28 | next ›
Discussion Overview
groupcpan-workers @
categoriesperl
postedJan 12, '16 at 12:53a
activeJan 18, '16 at 10:52p
posts28
users8
websitecpan.org

People

Translate

site design / logo © 2017 Grokbase