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?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
David W.
  • 105,218
  • 39
  • 216
  • 337

4 Answers4

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
mob
  • 117,087
  • 18
  • 149
  • 283
  • 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. – David W. Aug 20 '13 at 19:14
6

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

brian d foy
  • 129,424
  • 31
  • 207
  • 592
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.
"
Oesor
  • 6,632
  • 2
  • 29
  • 56
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"
);
Ecuador
  • 1,014
  • 9
  • 26