Perl构build,unit testing,代码覆盖率:一个完整的工作示例
大多数Stackoverflow的答案,我已经发现了有关的Perl构build过程和unit testing和代码覆盖面只是指向CPAN的文档。 指向CPAN模块绝对没有错,因为这是完整的文档应该驻留的地方。 但是,在许多情况下,我找不到完整的工作代码示例。
我一直在search整个互联网上的实际工作代码示例,我可以下载或粘贴到我的IDE中,就像典型的教程“Hello World”示例源代码,但是一个演示使用unit testing和代码构build过程的示例覆盖率分析。 有没有人有一个完整的工作项目的小例子来演示这些技术和stream程?
(我有一个小例子,我会用它回答我自己的问题,但也许有其他SO用户比我提出的例子更好的例子。)
我花了一段时间,它也采取了从一些不同来源的小片段,并融合在一起,但我认为我有一个小工作的例子,足以向Perl新手Perl演示程序包括unit testing和代码覆盖分析和报告。 (我在Windows XP Pro PC上使用ActiveState ActivePerl v5.10.0, Module :: Build , Test :: More , Devel :: Cover )
从您的Perl项目的目录开始,然后在您的项目目录下创build一个“lib”目录和一个“t”目录:
HelloPerlBuildWorld | |----------> lib | |----------> t
在“lib”目录中,创build一个名为“HelloPerlBuildWorld.pm”的文本文件。 这个文件是你将要构build和testing的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”目录下,创build一个名为“HelloPerlBuildWorld.t”的文本文件。 这个文件是你的unit testing脚本,它将试图完全testing你的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一个名为“Build.PL”的文本文件。 这个文件将会创build你将在以后使用的构build脚本。 将以下内容粘贴到此文件中:
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();
这就是你需要的所有文件。 现在从顶层项目目录的命令行中input以下命令:
perl Build.PL
您将看到类似于以下内容的内容:
Checking prerequisites... Looks good Creating new 'Build' script for 'HelloPerlBuildWorld' version '0.1'
现在你应该可以用下面的命令运行你的unit testing:
Build test
并看到类似的东西:
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)
要使用代码覆盖率分析来运行unit testing,请尝试以下操作:
Build testcover
你会看到这样的顺序:
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.
(有人请告诉我如何configurationCover来忽略所有的Perl库,只是在我写的单个文件中报告给我,根据CPAN文档,我无法使用Cover filter工作!
现在,如果刷新顶级目录,则可以看到名为“cover_db”的新子目录。 进入该目录,双击“coverage.html”文件,在您最喜欢的网页浏览器中打开代码覆盖率报告。 它给你一个很好的彩色编码的超文本报告,你可以点击你的文件名,在实际源代码旁边的报告中查看Perl模块的详细语句,分支,条件和子程序覆盖率统计信息。 您可以在本报告中看到,我们并没有覆盖“bye()”例程,还有一行无法访问的代码没有按照我们的预期覆盖。
代码覆盖率报告的快照http://www.leucht.comhttp://img.dovov.comCodeCoverageExample.jpg
还有一件事可以帮助在你的IDE中实现这个过程的自动化,就是制作一些更多的“Build.PL”types的文件,这些文件明确地执行我们在命令行手动执行的一些构build目标。 例如,我使用以下内容的“BuildTest.PL”文件:
use strict; use warnings; use Module::Build; my $build = Module::Build->resume ( properties => { config_dir => '_build', }, ); $build->dispatch('build'); $build->dispatch('test');
然后,我将IDE设置为通过单击鼠标来执行此文件(通过“perT BuiltTest.PL”),它会自动从IDE运行我的unit testing代码,而不是从命令行手动执行。 将“dispatch('test')”replace为“dispatch('testcover')”,以便自动执行代码覆盖。 键入“构build帮助”,获取可从Module :: Build获得的构build目标的完整列表。
为了回应库尔特,我会提出这个替代他的BuiltTest.PL脚本。
use strict; use warnings; use Module::Build; my $build = Module::Build->resume ( properties => { config_dir => '_build', }, ); $build->dispatch('build'); $build->dispatch('test');
它重用Build.PL构build的数据库(因此假定已经运行)。
这个非常有用的module-starter
生成了一个易于使用的框架项目,它处理模块安装,创build文档和模块文件的良好布局,以及 – 我认为 – 代码覆盖支持。 对于任何Perl模块相关的努力来说,IMO都是一个很好的开始。
另外:使用CPAN相关的工具,例如Module::Build
,即使是可能永远不会公开发布的模块, 也是一个非常好的主意 。
我介绍了中级Perl以及掌握Perl 。 不过,库尔特给出了一个很好的总结。
尽pipe如此,我将所有这些结合到一个使用Module :: Release的发行脚本中。 我input一个命令,这一切都发生。
(披露:我是作者)
一旦你把所有的东西按上面的描述sorting,你就可以进行下一步操作,并使用Devel :: CoverX :: Covered进行例如
- 给定一个源文件,列出覆盖该源文件的testing文件。 这可以在文件,子例程和行级上完成。
- 给定一个testing文件,列出该testing文件覆盖的源文件和子目录。
- 给定一个源文件,可以有效地报告每行的覆盖细节或子文件。
请参阅具体命令行示例的摘要 。
在Devel :: PerlySense中 ,Emacs支持在源代码缓冲区( 屏幕截图 )中显示覆盖信息,并导航到覆盖testing文件。