How can I test STDERR with Test::More?
Asked Answered
F

4

6

I am writing some tests using Test::More, and one of the functions I'm testing prints to STDERR. I'd like to test the output to STDERR, but am a little unsure how to do this. I know I'm close. This works:

use strict;
use warnings;
use feature qw(say);

close STDERR;
open STDERR, ">", \my $error_string;

say STDERR "This is my message";
say qq(The \$error_string is equal to "$error_string");

This prints out:

The $error_string is equal to "This is my message
"

However, I don't want to close STDERR. I merely want to dup it.

I've tried this:

use strict;
use warnings;
use feature qw(say);

open my $error_fh, ">", my $error_string;
open STDERR, ">&", $error_fh;

say STDERR "This is my message";
close $error_fh;
say qq(The \$error_string is equal to "$error_string");

But, $error_string is blank.

What am I doing wrong?

Fideliafidelio answered 20/8, 2013 at 18:44 Comment(0)
E
6

For me, open STDERR, ">&", $error_fh (along with open STDERR, ">&" . fileno($error_fh)) does not return a true value. I think the >& mode might be a pretty direct syntactic sugar for a dup system call, which wouldn't work on a pseudo-filehandle like $error_fh.

How about localizing STDERR?

{
    local *STDERR = *$error_fh;
    say STDERR "something";
}
# STDERR restored
Evaporite answered 20/8, 2013 at 18:58 Comment(1)
Dang. I thought I had use autodie; turned on. When I do add it, I get Can't open 'GLOB(0x7fcb82829808)' with mode '>&': 'Bad file descriptor' at ./test.pl line 11. Localizing STDERR should do the trick.Fideliafidelio
I
6

Test::Output can do it, and it now uses Capture::Tiny to catch the edge cases.

Inexpert answered 21/8, 2013 at 4:0 Comment(0)
S
2
#  perl -MPerlIO::tee -MData::Printer -e 'my $output; STDERR->push_layer(tee=> \$output); warn "Danger, Will Robinson!"; p($output);'
Danger, Will Robinson! at -e line 1.
"Danger, Will Robinson! at -e line 1.
"
Semiquaver answered 20/8, 2013 at 18:56 Comment(0)
O
0

A couple of years after this question, Test2 came out which eventually replaced Test::More (Test::More is simply a wrapper over Test2 now). So testing STDERR nowadays is done simply with Test2::Tools::Warnings.

like(
    warning { warn 'my error' },
    qr/my error/,
    "Got expected warning"
);
Oaf answered 30/6, 2022 at 4:53 Comment(1)
Test2::Tools::Warnings specifically tests whether or not warn is called, by hooking into $SIG{__WARN__}. This doesn't help if you write to STDERR in some other way -- for that, use Capture::Tiny (or one of the other mentioned packages).Valuable

© 2022 - 2024 — McMap. All rights reserved.