81

Hầu hết các câu trả lời Stackoverflow mà tôi đã tìm thấy liên quan đến quá trình xây dựng Perl và kiểm tra đơn vị và mã bảo hiểm đơn giản chỉ cho tôi CPAN cho tài liệu ở đó. Hoàn toàn không có gì sai khi chỉ vào các mô-đun CPAN vì đó là nơi mà tài liệu đầy đủ được cho là cư trú. Tuy nhiên, tôi đã gặp khó khăn trong việc tìm kiếm các ví dụ mã làm việc hoàn chỉnh trong nhiều trường hợp.Xây dựng Perl, thử nghiệm đơn vị, mã bảo hiểm: Một ví dụ làm việc hoàn chỉnh

Tôi đã tìm kiếm trên Internet các mẫu mã hoạt động thực tế mà tôi có thể tải xuống hoặc dán vào IDE của mình, như mã nguồn ví dụ "Hello World" hướng dẫn điển hình của bạn, nhưng ví dụ minh họa quá trình xây dựng kiểm tra đơn vị và phân tích phạm vi mã. Có ai có một ví dụ nhỏ về một dự án làm việc hoàn chỉnh thể hiện những công nghệ và quy trình này không?

(tôi có một ví dụ làm việc nhỏ và tôi sẽ trả lời câu hỏi của riêng tôi với nó, nhưng có lẽ là SO những người dùng khác có ví dụ tốt hơn so với những cái tôi đã đưa ra.)

Trả lời

101

Phải mất tôi một lúc và tôi cũng lấy những đoạn trích nhỏ từ nhiều nguồn khác nhau và làm tan chảy chúng lại với nhau, nhưng tôi nghĩ tôi có một ví dụ nhỏ làm việc đủ để minh họa cho một người mới Perl quy trình xây dựng Perl bao gồm kiểm thử đơn vị và phân tích phạm vi mã & Báo cáo. (Tôi đang sử dụng ActiveState ActivePerl v5.10.0 trên Pro PC Windows XP, Module::Build, Test::More, Devel::Cover)

Bắt đầu với một thư mục cho dự án Perl của bạn và sau đó tạo ra một "lib" thư mục và "t" thư mục dưới thư mục dự án của bạn:

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

Trong thư mục "lib", tạo tệp văn bản có tên "HelloPerlBuildWorld.pm". Tệp này là mô-đun Perl của bạn mà bạn sẽ xây dựng và thử nghiệm. Dán nội dung sau đây vào tệp này:

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; 

Trong thư mục "t", tạo tệp văn bản có tên "HelloPerlBuildWorld.t". Tệp này là tập lệnh thử nghiệm đơn vị của bạn sẽ cố gắng kiểm tra đầy đủ mô-đun Perl của bạn ở trên. Dán nội dung sau đây vào tệp này:

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"); 

Bây giờ sao lưu trong thư mục dự án cấp cao nhất của bạn, tạo tệp văn bản có tên "Build.PL". Tệp này sẽ tạo tập lệnh xây dựng của bạn mà bạn sẽ sử dụng sau này. Dán nội dung sau đây vào tệp này:

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 protected]>', 
    build_requires => { 
     'Test::More' => '0.10', 
    }, 
); 

$builder->create_build_script(); 

Đó là tất cả các tệp bạn cần.Bây giờ từ dòng lệnh trong thư mục dự án cấp cao nhất, gõ lệnh sau:

perl Build.PL 

Bạn sẽ thấy một cái gì đó tương tự như sau:

Checking prerequisites... 
Looks good 

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

Bây giờ bạn sẽ có thể chạy thử nghiệm đơn vị của bạn với lệnh sau đây:

Build test 

Và thấy một cái gì đó tương tự như sau:

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) 

Để chạy thử nghiệm đơn vị của bạn với phân tích mã số bảo hiểm, hãy thử này:

Build testcover 

Và bạn sẽ thấy một cái gì đó về trình tự này:

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. 

(Có người hãy cho tôi biết thế nào để cấu hình Cover để bỏ qua tất cả các thư viện Perl ngoại trừ và chỉ báo cáo lại cho tôi trên tập tin duy nhất của tôi mà tôi đã viết. Tôi không thể yêu cầu lọc Cover hoạt động theo tài liệu CPAN!)

Bây giờ nếu bạn làm mới thư mục cấp cao nhất, bạn có thể thấy thư mục con mới có tên là "cover_db". Đi vào thư mục đó và nhấp đúp vào tệp "coverage.html" để mở báo cáo mức độ phù hợp mã trong trình duyệt web ưa thích của bạn. Nó cung cấp cho bạn một báo cáo siêu văn bản được mã hóa màu sắc tốt nơi bạn có thể nhấp vào tên tệp của bạn và xem chi tiết câu lệnh, chi nhánh, điều kiện, thống kê bao phủ chương trình con cho mô-đun Perl của bạn ngay trong báo cáo bên cạnh mã nguồn thực tế. Bạn có thể thấy trong báo cáo này rằng chúng tôi không bao gồm thường lệ "bye()" và cũng có một dòng mã không thể truy cập được mà không được bảo hiểm như chúng tôi mong đợi.

snapshot of code coverage report http://www.leucht.com/images/CodeCoverageExample.jpg

Một điều nữa bạn có thể làm để giúp tự động hóa quá trình này trong IDE của bạn là làm cho một số chi tiết "Build.PL" file kiểu đó thực hiện một cách rõ ràng một số các mục tiêu xây dựng mà chúng ta đã làm ở trên cách thủ công từ dòng lệnh. Ví dụ, tôi sử dụng một "BuildTest.PL" tập tin với nội dung sau:

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

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

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

Sau đó, tôi lập IDE của tôi để thực hiện tập tin này (thông qua "perl BuiltTest.PL") với một click chuột duy nhất và nó tự động chạy mã kiểm tra đơn vị của tôi từ IDE thay vì tôi thực hiện nó theo cách thủ công từ dòng lệnh. Thay thế "dispatch ('test')" bằng "dispatch ('testcover')" để thực hiện bảo hiểm mã tự động. Nhập "Xây dựng trợ giúp" để có danh sách đầy đủ các mục tiêu xây dựng có sẵn từ Mô-đun :: Xây dựng.

+1

Ý tưởng của bạn để thiết lập một tệp BuiltTest.PL không tốt cho tôi. Tại sao bạn không thể viết một kịch bản 'Build build' và' Build test'? –

+2

Leon, bạn đang đề xuất một kịch bản perl mà làm cho các cuộc gọi dòng lệnh? Nếu vậy, tôi không muốn thực hiện các cuộc gọi dòng lệnh nếu có một cách OO để thực hiện các cuộc gọi lập trình như trong tệp ví dụ BuiltTest.PL. –

+1

Điều đó không cần thiết, hãy xem câu trả lời của riêng tôi –

14

Để trả lời Kurt, tôi sẽ đề xuất phương án này cho kịch bản lệnh BuiltTest.PL của anh ấy.

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

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

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

Nó reuses xây dựng cơ sở dữ liệu bằng Build.PL (và do đó giả định rằng đã chạy).

+0

Hoàn hảo! Cảm ơn, Leon. Tôi biết có điều gì đó sai với ví dụ của mình, nhưng tôi vẫn còn mới mẻ với công cụ xây dựng perl này! :-) –

12

Tôi bao gồm điều này trong Intermediate Perl cũng như Mastering Perl. Kurt, tuy nhiên, đã đưa ra một bản tóm tắt tốt đẹp.

Tôi kết hợp tất cả điều này thành tập lệnh phát hành sử dụng Module::Release. Tôi gõ một lệnh và tất cả đều xảy ra.

12

Công cụ tuyệt vời hữu ích module-starter tạo ra một dự án bộ xương dễ sử dụng, xử lý cài đặt mô-đun, tạo tài liệu và bố cục tốt cho các tệp mô-đun để sống và - I nghĩ - hỗ trợ bảo hành mã. IMO là một khởi đầu tuyệt vời cho bất kỳ nỗ lực nào liên quan đến mô-đun Perl.

Ngoài ra: sử dụng các công cụ liên quan đến CPAN như Module::Build - ngay cả đối với các mô-đun có khả năng sẽ không bao giờ được phát hành công khai - is a very good idea.

7

(tiết lộ: Tôi là tác giả)

Một khi bạn đã sắp xếp tất cả mọi thứ như đã mô tả ở trên, bạn có thể thực hiện bước tiếp theo và sử dụng Devel::CoverX::Covered để ví dụ

  • Cung cấp tệp nguồn, liệt kê các tệp thử nghiệm cung cấp mức độ phù hợp cho tệp nguồn đó. Điều này có thể được thực hiện trên một tập tin, thường trình phụ và mức hàng.
  • Cho một tệp thử nghiệm, liệt kê các tệp nguồn và các tệp phụ được bao phủ bởi tệp kiểm tra đó.
  • Cung cấp tệp nguồn, báo cáo hiệu quả về chi tiết bảo hiểm cho mỗi hàng hoặc phụ.

Xem ví dụ synopsis cho ví dụ dòng lệnh cụ thể.

Trong Devel::PerlySense có hỗ trợ Emacs để hiển thị thông tin bảo hiểm trong bộ đệm mã nguồn (screen shot) và để điều hướng đến/từ bao gồm tệp thử nghiệm.

Các vấn đề liên quan