Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I collect coverage from child processes when running `cover -test`, and not otherwise? (Devel::Cover)

(I think I've seen the answer to this, but I can't find it again. The closest I have come across is this question).

I am hacking on prt and am trying to get full coverage data for my changes. Some of my new tests call system($^X, 'prt', ...) to run child processes. I then test the output of those processes. However, Devel::Cover does not collect coverage data in the child processes. How do I collect that data, without causing Devel::Cover to run when I do a regular make test? Currently I have an ugly workaround (see below), but I think there must be a simpler way.

A full MCVE is here. Command line to copy, for your convenience:

git clone https://github.com/cxw42/multi-process-devel-cover-test.git ; cd multi-process-devel-cover-test ; perl Makefile.PL ; make ; cover -test

Comment out line 11 of t/01-help.t for the workaround described below.

Edit The reason I am using system is to get to 100% coverage on -h/--help/--version. Those switches are handled by Getopt::Long, which calls exit() automatically. If necessary, I can use -exitval=>NOEXIT and handle the exit in my own code.

Things that don't work

PERL5OPT

$ PERL5OPT=-MDevel::Cover=-silent,1 cover -test
/home/cxw/perl5/perlbrew/perls/perlcygbrew-5.26.2-1/bin/cover shouldn't be run with coverage turned on.

HARNESS_PERL_SWITCHES+cover

$ HARNESS_PERL_SWITCHES=-MDevel::Cover=-silent,1 cover -test
...
t/01-help.t .. # Devel::Cover not covering
...
----- ------ ------ ------ ------ ------ ------ ------
File    stmt   bran   cond    sub    pod   time  total
----- ------ ------ ------ ------ ------ ------ ------
Total    n/a    n/a    n/a    n/a    n/a    n/a    n/a
----- ------ ------ ------ ------ ------ ------ ------

HARNESS_PERL_SWITCHES+EUMM make test

$ HARNESS_PERL_SWITCHES=-MDevel::Cover=-silent,1 make test
...
t/01-help.t .. # Devel::Cover not covering
...
$ (export HARNESS_PERL_SWITCHES=-MDevel::Cover=-silent,1 ; make test)
...
t/01-help.t .. # Devel::Cover not covering
...

Current workaround

At present, the only way I have found is to manually add -MDevel::Cover to the command line when I call system. Inspired by this answer and the corresponding tests, I have the following workaround:

# Detect whether Devel::Cover is running
my $is_covering = !!(eval 'Devel::Cover::get_coverage()');
my @perl = ($^X, $is_covering ? ('-MDevel::Cover=-silent,1') : ());
diag $is_covering ? 'Devel::Cover running' : 'Devel::Cover not covering';

# Pass the Devel::Cover option, if any, to the child process
system(@perl, 'prt', ...);

In the MCVE, the workaround is here and it is used here.

like image 807
cxw Avatar asked Jul 02 '19 16:07

cxw


1 Answers

I think that this, or something similar, is probably about the best you can do.

Devel::Cover is pretty much designed as a development tool and, as such, has the assumption that you will be testing one project at a time. It seems that you are really wanting to test two projects here. If that's not the case then perhaps there is a better way of combining the parts than using system?

But if your current solution is the best way of combining this code then I'm not sure there's a better way to get complete coverage. You could perhaps be explicit and set an environment variable if you want coverage, for example, or you could set $PERL5OPT rather than change the system call, but essentially that's the same solution.

like image 86
pjcj Avatar answered Oct 10 '22 09:10

pjcj