Xây dựng Perl, kiểm thử đơn vị, phạm vi mã: Một ví dụ làm việc hoàn chỉnh


86

Hầu hết các câu trả lời của 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à phạm vi mã chỉ đơn giản là trỏ tôi đến CPAN để xem tài liệu ở đó. Hoàn toàn không có gì sai khi trỏ đến các mô-đun CPAN vì đó là nơi chứa đầy đủ tài liệu. Tuy nhiên, tôi đã gặp khó khăn khi tìm các ví dụ mã làm việc hoàn chỉnh trong nhiều trường hợp.

Tôi đã tìm kiếm khắp nơi trên Internet cho các mẫu mã làm việc thực tế mà tôi có thể tải xuống hoặc dán vào IDE của mình, chẳng hạn như mã nguồn ví dụ điển hình của hướng dẫn "Hello World" của bạn, nhưng ví dụ minh họa quy trình xây dựng với kiểm tra đơn vị và mã phân tích vùng phủ sóng. 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 mình với nó, nhưng có lẽ có những người dùng SO khác có ví dụ tốt hơn những ví dụ mà tôi đã nghĩ ra.)

Câu trả lời:


105

Tôi đã mất một lúc và tôi cũng phải lấy các đoạn trích nhỏ từ một số nguồn khác nhau và làm tan chúng lại với nhau, nhưng tôi nghĩ rằng tôi có một ví dụ làm việc nhỏ đủ chứng minh cho người mới chơi Perl về quy trình xây dựng Perl bao gồm kiểm tra đơn vị và phạm vi mã phân tích và báo cáo. (Tôi đang sử dụng ActiveState ActivePerl v5.10.0 trên PC chạy Windows XP Pro, Mô-đun :: Xây dựng , Kiểm tra :: Thêm , Devel :: Bìa )

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

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

Trong thư mục "lib", tạo một 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 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 một tệp văn bản có tên "HelloPerlBuildWorld.t". Tệp này là tập lệnh kiểm tra đơ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 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 một tệp văn bản có tên "Build.PL". Tệp này sẽ tạo các 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 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_addy@goes.here>',
    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, hãy nhập 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 các bài kiểm tra đơn vị của mình bằng lệnh sau:

Build test

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

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ức độ phù hợp mã, hãy thử cách này:

Build testcover

Và bạn sẽ thấy một cái gì đó theo thứ 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.

(Ai đó vui lòng cho tôi biết cách định 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 về tệp duy nhất mà tôi đã viết. Tôi không thể làm cho tính năng 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 của mình, bạn có thể thấy một thư mục con mới có tên "cover_db". Đi vào thư mục đó và nhấp đúp vào tệp "secure.html" để mở báo cáo phạm vi mã trong trình duyệt web yêu 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 đẹp mắt, nơi bạn có thể nhấp vào tên tệp của mình và xem các thống kê chi tiết về báo cáo, nhánh, điều kiện, mức độ phù hợp chương trình con cho mô-đun Perl của bạn ngay tại 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 đề cập đến quy trình "tạm biệt ()" và cũng có một dòng mã không thể truy cập được không được đề cập như chúng tôi mong đợi.

ảnh chụp nhanh của báo cáo mức độ mã
(nguồn: leucht.com )

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 mình là tạo thêm một số tệp loại "Build.PL" thực hiện rõ ràng một số mục tiêu xây dựng mà chúng tôi đã thực hiện ở trên theo cách thủ công từ dòng lệnh. Ví dụ: tôi sử dụng tệp "BuildTest.PL" 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 thiết lập IDE của mình để thực thi tệp này (thông qua "perl BuiltTest.PL") bằng một cú nhấp chuộ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 thủ công từ dòng lệnh. Thay thế "công văn ('kiểm tra')" bằng "công văn ('testcover')" để thực thi phạm vi mã tự động. Nhập "Trợ giúp xây dựng" để 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 BuiltTest.PL nghe có vẻ không tốt với tôi. Tại sao bạn không thể chỉ viết một kịch bản Build buildvà sau đó Build test?
Leon Timmermans 10/02/09

2
Leon, bạn có đang đề xuất một tập lệnh perl thực hiện các lệnh gọi dòng lệnh không? 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 theo chương trình như trong tệp BuiltTest.PL ví dụ.
Kurt W. Leucht 10/02/09

1
Điều đó không cần thiết, hãy xem câu trả lời của riêng tôi
Leon Timmermans 10/02/09

2
Mô-đun :: Chỉ xây dựng không dành cho CPAN. Bạn vẫn có thể nhận được tất cả các tính năng từ các công cụ CPAN khác nhau ngay cả khi nó không có trên CPAN. Bạn vẫn có thể xây dựng, kiểm tra, phân phối và cài đặt nó với cùng một quy trình mặc dù nó là một mô-đun riêng tư.
brian d foy

4
Để lọc kết quả trong Devel :: Cover, tôi thêm các tùy chọn vào $ENV{HARNESS_PERL_SWITCHES}. Ví dụ: -MDevel::Cover=+ignore,.t$,+inc,/app/lib,-select,MyModule.pmđâu /app/liblà thư viện ứng dụng-riêng và MyModule.pmlà mô-đun đang được kiểm tra.
Michael Carman

14

Để đáp lại Kurt, tôi sẽ đề xuất thay thế này cho tập lệnh BuildTest.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ó sử dụng lại cơ sở dữ liệu được xây dựng bởi Build.PL (và do đó giả định rằng nó đã chạy).


Hoàn hảo! Cảm ơn, Leon. Tôi biết có điều gì đó không ổn với ví dụ của mình, nhưng bản thân tôi vẫn chưa quen với công cụ xây dựng perl này! :-)
Kurt W. Leucht 10/02/09

12

Tôi đề cập đến vấn đề này trong Perl trung cấp 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ả những điều này thành một tập lệnh phát hành bằng cách sử dụng Module :: Release . Tôi gõ một lệnh và tất cả đều xảy ra.


12

Sự hữu ích tuyệt vời module-startertạo ra một dự án khung dễ sử dụng, xử lý việc cài đặt mô-đun, tạo tài liệu và bố cục tốt cho các tệp mô-đun, và - tôi nghĩ - hỗ trợ phạm vi bảo vệ 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ó thể sẽ không bao giờ được phát hành công khai - là một ý tưởng rất hay .


7

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

Khi bạn đã sắp xếp 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 cho ví dụ:

  • Đưa ra một tệp nguồn, hãy liệt kê các tệp thử nghiệm cung cấp phạm vi cho tệp nguồn đó. Điều này có thể được thực hiện trên một tệp, quy trình phụ và cấp hàng.
  • Đưa ra một tệp thử nghiệm, hãy liệt kê các tệp nguồn và con được bao phủ bởi tệp thử nghiệm đó.
  • Với một tệp nguồn, hãy báo cáo một cách hiệu quả về chi tiết mức độ phù hợp trên mỗi hàng hoặc phụ.

Xem tóm tắt để biết các ví dụ cụ thể về dòng lệnh.

Trong Devel :: PerlySense có hỗ trợ Emacs để hiển thị thông tin về phạm vi trong bộ đệm mã nguồn ( ảnh chụp màn hình ) và điều hướng đến / đi từ các tệp kiểm tra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.