web-dev-qa-db-fra.com

Construction Perl, tests unitaires, couverture de code: un exemple de travail complet

La plupart des réponses Stackoverflow que j'ai trouvées en ce qui concerne le processus de construction Perl et les tests unitaires et la couverture de code me dirigent simplement vers CPAN pour la documentation. Il n'y a absolument rien de mal à pointer vers les modules CPAN car c'est là que la documentation complète est censée résider. J'ai eu du mal à trouver des exemples de code de travail complets dans de nombreux cas, cependant.

J'ai cherché partout sur Internet des exemples de code de travail réels que je peux télécharger ou coller dans mon IDE, comme votre exemple de code source de tutoriel "Hello World", mais d'un exemple qui illustre le processus de construction avec des tests unitaires et du code analyse de couverture. Quelqu'un at-il un petit exemple d'un projet de travail complet qui démontre ces technologies et processus?

(J'ai un petit exemple de travail et je vais répondre à ma propre question, mais il y a probablement d'autres SO utilisateurs qui ont de meilleurs exemples que ceux que j'ai inventés). )

84
Kurt W. Leucht

Cela m'a pris du temps et il m'a également fallu prendre de petits extraits de différentes sources et les fusionner, mais je pense avoir un petit exemple de travail qui démontre suffisamment à un débutant Perl le processus de construction de Perl, y compris les tests unitaires et la couverture de code analyse et rapports. (J'utilise ActiveState ActivePerl v5.10.0 sur un Windows XP Pro PC, Module :: Build , Test :: Plus , Devel :: Cover )

Commencez avec un répertoire pour votre projet Perl puis créez un répertoire "lib" et un répertoire "t" sous votre répertoire de projet:

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

Dans le répertoire "lib", créez un fichier texte nommé "HelloPerlBuildWorld.pm". Ce fichier est votre module Perl que vous allez construire et tester. Collez le contenu suivant dans ce fichier:

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;

Dans le répertoire "t", créez un fichier texte nommé "HelloPerlBuildWorld.t". Ce fichier est votre script de test unitaire qui tentera de tester complètement votre module Perl ci-dessus. Collez le contenu suivant dans ce fichier:

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

Maintenant, sauvegardez dans votre répertoire de projet de niveau supérieur, créez un fichier texte nommé "Build.PL". Ce fichier créera vos scripts de construction que vous utiliserez plus tard. Collez le contenu suivant dans ce fichier:

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

C'est tous les fichiers dont vous avez besoin. À partir de la ligne de commande du répertoire de projet de niveau supérieur, tapez la commande suivante:

Perl Build.PL

Vous verrez quelque chose de semblable au suivant:

Checking prerequisites...
Looks good

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

Vous devriez maintenant pouvoir exécuter vos tests unitaires avec la commande suivante:

Build test

Et voyez quelque chose de similaire à ceci:

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)

Pour exécuter vos tests unitaires avec une analyse de couverture de code, essayez ceci:

Build testcover

Et vous verrez quelque chose dans l'ordre de ceci:

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.

(Quelqu'un s'il vous plaît, dites-moi comment configurer Cover pour ignorer toutes les bibliothèques Perl, sauf pour me faire rapport sur mon seul fichier que j'ai écrit. Je n'ai pas pu faire fonctionner le filtrage Cover selon le Documentation CPAN!)

Maintenant, si vous actualisez votre répertoire de niveau supérieur, vous pouvez voir un nouveau sous-répertoire appelé "cover_db". Allez dans ce répertoire et double-cliquez sur le fichier "coverage.html" pour ouvrir le rapport de couverture du code dans votre navigateur Web préféré. Il vous donne un rapport hypertexte à code couleur agréable où vous pouvez cliquer sur le nom de votre fichier et voir les statistiques détaillées de la déclaration, de la branche, de l'état et de la couverture des sous-programmes pour votre module Perl ici dans le rapport à côté du code source réel. Vous pouvez voir dans ce rapport que nous n'avons pas du tout couvert la routine "bye ()" et qu'il y a aussi une ligne de code inaccessible qui n'a pas été couverte comme prévu.

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

Une autre chose que vous pouvez faire pour automatiser ce processus dans votre IDE consiste à créer des fichiers de type "Build.PL" supplémentaires qui exécutent explicitement certaines des cibles de construction que nous avons faites ci-dessus manuellement à partir de la Par exemple, j'utilise un fichier "BuildTest.PL" avec le contenu suivant:

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

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

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

Ensuite, j'ai configuré mon IDE pour exécuter ce fichier (via "Perl BuiltTest.PL") d'un simple clic de souris et il exécute automatiquement mon code de test unitaire à partir du IDE au lieu que je le fasse manuellement à partir de la ligne de commande. Remplacez "dispatch ('test')" par "dispatch ('testcover')" pour l'exécution automatisée de la couverture de code. Tapez "Build help" pour une liste complète des builds cibles disponibles à partir de Module :: Build.

103
Kurt W. Leucht

En réponse à Kurt, je proposerais cette alternative à son script BuiltTest.PL.

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

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

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

Il réutilise la base de données créée par Build.PL (et suppose donc que déjà exécuté).

14
Leon Timmermans

Je couvre cela dans Perl intermédiaire ainsi que Mastering Perl . Kurt, cependant, a donné un bon résumé.

Cependant, je combine tout cela dans un script de version en utilisant Module :: Release . Je tape une commande et tout se passe.

12
brian d foy

Le fantastiquement utile module-starter génère un projet squelette facile à utiliser qui gère l'installation du module, la création de documentation et une bonne mise en page pour les fichiers du module, et - je pense - prise en charge de la couverture du code. C'est IMO un excellent début pour toute entreprise liée au module Perl.

Aussi: en utilisant des outils liés au CPAN comme Module::Build - même pour les modules qui ne seront probablement jamais publiés - c'est une très bonne idée .

12
Gaurav

(divulgation: je suis l'auteur)

Une fois que vous avez tout trié comme décrit ci-dessus, vous pouvez passer à l'étape suivante et utiliser Devel :: CoverX :: Covered pour par exemple.

  • Étant donné un fichier source, répertoriez les fichiers de test qui couvrent ce fichier source. Cela peut être fait au niveau d'un fichier, d'une sous-routine et d'une ligne.
  • Étant donné un fichier de test, répertoriez les fichiers source et les sous-marins couverts par ce fichier de test.
  • Étant donné un fichier source, créez un rapport efficace sur les détails de couverture par ligne ou sous-fichier.

Voir synopsis pour des exemples concrets de ligne de commande.

Dans Devel :: PerlySense il y a le support Emacs pour afficher les informations de couverture dans le tampon du code source ( capture d'écran ), et pour naviguer vers/depuis les fichiers de test de couverture.

7
jplindstrom