Programing

Perl 빌드, 단위 테스트, 코드 커버리지 : 완전한 작동 예제

crosscheck 2020. 9. 22. 07:30
반응형

Perl 빌드, 단위 테스트, 코드 커버리지 : 완전한 작동 예제


Perl 빌드 프로세스 및 단위 테스트 및 코드 커버리지와 관련하여 찾은 대부분의 Stackoverflow 답변은 해당 문서에 대한 CPAN을 가리 킵니다. CPAN 모듈을 가리키는 데 전혀 문제가 없습니다. 전체 문서가 있어야하기 때문입니다. 그래도 많은 경우에 완전한 작동 코드 예제를 찾는 데 어려움을 겪었습니다.

일반적인 자습서 "Hello World"예제 소스 코드와 같이 IDE에 다운로드하거나 붙여 넣을 수있는 실제 작업 코드 샘플을 인터넷에서 검색했지만 단위 테스트 및 코드를 사용하여 빌드 프로세스를 보여주는 예제 커버리지 분석. 누구든지 이러한 기술과 프로세스를 보여주는 완전한 작업 프로젝트의 작은 예를 가지고 있습니까?

(저는 작은 작업 예제를 가지고 있으며 제 질문에 답할 것입니다. 그러나 제가 생각해 낸 것보다 더 나은 예제를 가진 다른 SO 사용자가있을 것입니다.)


시간이 좀 걸렸고 여러 소스에서 작은 스 니펫을 가져 와서 함께 녹이는데도 걸렸지 만 Perl 초보자에게 단위 테스트 및 코드 커버리지를 포함한 Perl 빌드 프로세스를 충분히 보여주는 작은 작업 예제가 있다고 생각합니다. 분석 및보고. ( Windows XP Pro PC, Module :: Build , Test :: More , Devel :: Cover 에서 ActiveState ActivePerl v5.10.0을 사용하고 있습니다. )

Perl 프로젝트의 디렉토리로 시작한 다음 프로젝트 디렉토리 아래에 "lib"디렉토리와 "t"디렉토리를 만듭니다.

HelloPerlBuildWorld
        |
        |----------> lib
        |
        |----------> t

"lib"디렉토리에서 "HelloPerlBuildWorld.pm"이라는 텍스트 파일을 만듭니다. 이 파일은 빌드하고 테스트 할 Perl 모듈입니다. 이 파일에 다음 내용을 붙여 넣으십시오.

use strict;
use warnings;
package HelloPerlBuildWorld;

$HelloPerlBuildWorld::VERSION = '0.1';

sub hello {
   return "Hello, Perl Build World!";
}

sub bye {
   return "Goodbye, cruel world!";
}

sub repeat {
   return 1;
}

sub argumentTest {
    my ($booleanArg) = @_;

    if (!defined($booleanArg)) {
        return "null";
    }
    elsif ($booleanArg eq "false") {
        return "false";
    }
    elsif ($booleanArg eq "true") {
        return "true";
    }
    else {
        return "unknown";
    }

   return "Unreachable code: cannot be covered";
}

1;

"t"디렉토리에서 "HelloPerlBuildWorld.t"라는 텍스트 파일을 만듭니다. 이 파일은 위의 Perl 모듈을 완전히 테스트하려고 시도하는 단위 테스트 스크립트입니다. 이 파일에 다음 내용을 붙여 넣으십시오.

use strict;
use warnings;
use Test::More qw(no_plan);

# Verify module can be included via "use" pragma
BEGIN { use_ok('HelloPerlBuildWorld') };

# Verify module can be included via "require" pragma
require_ok( 'HelloPerlBuildWorld' );

# Test hello() routine using a regular expression
my $helloCall = HelloPerlBuildWorld::hello();
like($helloCall, qr/Hello, .*World/, "hello() RE test");

# Test hello_message() routine using a got/expected routine
is($helloCall, "Hello, Perl Build World!", "hello() IS test");

# Do not test bye() routine

# Test repeat() routine using a got/expected routine
for (my $ctr=1; $ctr<=10; $ctr++) {
    my $repeatCall = HelloPerlBuildWorld::repeat();
    is($repeatCall, 1, "repeat() IS test");
}

# Test argumentTest() 
my $argumentTestCall1 = HelloPerlBuildWorld::argumentTest();
is($argumentTestCall1, "null", "argumentTest() IS null test");

# Test argumentTest("true") 
my $argumentTestCall2 = HelloPerlBuildWorld::argumentTest("true");
is($argumentTestCall2, "true", "argumentTest() IS true test");

# Test argumentTest("false") 
my $argumentTestCall3 = HelloPerlBuildWorld::argumentTest("false");
is($argumentTestCall3, "false", "argumentTest() IS false test");

# Test argumentTest(123) 
my $argumentTestCall4 = HelloPerlBuildWorld::argumentTest(123);
is($argumentTestCall4, "unknown", "argumentTest() IS unknown test");

이제 최상위 프로젝트 디렉토리에 백업하고 "Build.PL"이라는 텍스트 파일을 만듭니다. 이 파일은 나중에 사용할 빌드 스크립트를 만듭니다. 이 파일에 다음 내용을 붙여 넣으십시오.

use strict;
use warnings;
use Module::Build;

my $builder = Module::Build->new(
    module_name         => 'HelloPerlBuildWorld',
    license             => 'perl',
    dist_abstract       => 'HelloPerlBuildWorld short description',
    dist_author         => 'Author Name <email_addy@goes.here>',
    build_requires => {
        'Test::More' => '0.10',
    },
);

$builder->create_build_script();

이것이 필요한 모든 파일입니다. 이제 최상위 프로젝트 디렉터리의 명령 줄에서 다음 명령을 입력합니다.

perl Build.PL

다음과 유사한 내용이 표시됩니다.

Checking prerequisites...
Looks good

Creating new 'Build' script for 'HelloPerlBuildWorld' version '0.1'

Now you should be able to run your unit tests with the following command:

Build test

And see something similar to this:

Copying lib\HelloPerlBuildWorld.pm -> blib\lib\HelloPerlBuildWorld.pm
t\HelloPerlBuildWorld....ok
All tests successful.
Files=1, Tests=18,  0 wallclock secs ( 0.00 cusr +  0.00 csys =  0.00 CPU)

To run your unit tests with code coverage analysis, try this:

Build testcover

And you'll see something on the order of this:

t\HelloPerlBuildWorld....ok
All tests successful.
Files=1, Tests=18, 12 wallclock secs ( 0.00 cusr +  0.00 csys =  0.00 CPU)
cover
Reading database from D:/Documents and Settings/LeuchKW/workspace/HelloPerlBuildWorld/cover_db


----------------------------------- ------ ------ ------ ------ ------ ------
File                                  stmt   bran   cond    sub   time  total
----------------------------------- ------ ------ ------ ------ ------ ------
D:/Perl/lib/ActivePerl/Config.pm       0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/ActiveState/Path.pm        0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/AutoLoader.pm              0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/B.pm                      18.6   16.7   13.3   19.2   96.4   17.6
 ...
[SNIP]
 ...
D:/Perl/lib/re.pm                      0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/strict.pm                 84.6   50.0   50.0  100.0    0.0   73.1
D:/Perl/lib/vars.pm                   44.4   36.4    0.0  100.0    0.0   36.2
D:/Perl/lib/warnings.pm               15.3   12.1    0.0   11.1    0.0   12.0
D:/Perl/lib/warnings/register.pm       0.0    0.0    n/a    0.0    n/a    0.0
blib/lib/HelloPerlBuildWorld.pm       87.5  100.0    n/a   83.3    0.0   89.3
Total                                  9.9    4.6    2.8   11.3  100.0    7.6
----------------------------------- ------ ------ ------ ------ ------ ------


Writing HTML output to D:/Documents and Settings/LeuchKW/workspace/HelloPerlBuildWorld/cover_db/coverage.html ...
done.

(Someone please tell me how to configure Cover to ignore all the Perl libraries except and just report back to me on my single file that I wrote. I could not get Cover filtering to work according to the CPAN documentation!)

Now if you refresh your top level directory, you can see a new subdirectory called "cover_db". Go into that directory and double click on the "coverage.html" file to open the code coverage report in your favorite web browser. It gives you a nice color coded hypertext report where you can click on your file name and see detailed statement, branch, condition, subroutine coverage statistics for your Perl module right there in the report next to the actual source code. You can see in this report that we did not cover the "bye()" routine at all and also there is a line of code that is unreachable that was not covered as we expected.

snapshot of code coverage report
(source: leucht.com)

One more thing you can do to help automate this process in your IDE is to make some more "Build.PL" type files that explicitly perform some of the build targets that we did above manually from the command line. For example, I use a "BuildTest.PL" file with the following content:

use strict;
use warnings;
use Module::Build;

my $build = Module::Build->resume (
  properties => {
    config_dir => '_build',
  },
);

$build->dispatch('build');
$build->dispatch('test');

Then I set up my IDE to execute this file (via "perl BuiltTest.PL") with a single mouse click and it automatically runs my unit test code from the IDE instead of me doing it manually from the command line. Replace the "dispatch('test')" with "dispatch('testcover')" for automated code coverage execution. Type "Build help" for a complete list of build targets that are available from Module::Build.


In response to Kurt, I would propose this alternative to his BuiltTest.PL script.

use strict;
use warnings;
use Module::Build;

my $build = Module::Build->resume (
  properties => {
    config_dir => '_build',
  },
);

$build->dispatch('build');
$build->dispatch('test');

It reuses the database build by Build.PL (and thus assumes that already ran).


I cover this in Intermediate Perl as well as Mastering Perl. Kurt, however, has given a nice summary.

I combine all of this into a release script using Module::Release though. I type one command and it all happens.


The fantastically helpful module-starter generates an easy-to-use skeleton project which handles module installation, creation of documentation and a good layout for module files to live in, and -- I think -- code coverage support. It's IMO a great start for any Perl module-related endeavour.

Also: using CPAN-related tools like Module::Build -- even for modules which are likely never going to be released publically -- is a very good idea.


(disclosure: I'm the author)

Once you have everything sorted as described above, you could take the next step and use Devel::CoverX::Covered to e.g.

  • Given a source file, list the test files that provide coverage to that source file. This can be done on a file, sub routine and row level.
  • Given a test file, list the source files and subs covered by that test file.
  • Given a source file, report efficiently on the coverage details per row, or sub.

See the synopsis for concrete command line examples.

In Devel::PerlySense there's Emacs support to display the coverage information in the source code buffer (screen shot), and to navigate to/from covering test files.

참고URL : https://stackoverflow.com/questions/533553/perl-build-unit-testing-code-coverage-a-complete-working-example

반응형