fpcunit/fr

From Lazarus wiki
Jump to: navigation, search

English (en) français (fr)

Vue d'ensemble

fpcunit est un framework de test d'unité à DUnit/JUnit/SUnit. Il vous permet d'écrire rapidement un ensemble de test pour une unité (logique) de code (pas nécessairement la même chose qu'une unité Pascal, bien que cela soit souvent le cas).

Les méthodologies de développement comme la conception dirigée par les tests (Test Driven Design, TDD) utilise ceci pour garantir que vos attentes/spécifications dans votre unité en premier, ensuite écrivez votre code principal, puis exécutez vos tests et améliorez le code jusqu'à ce que tous les tests passent.

Non seulement fpcunit vous permet dinspecter visuellement vos exécutions de tests, vous pouvez aussi collecter les résultats systématiquement (en utilisant la sortie XML), et l'utiliser pour comparer les versions pour p.ex. les tests de non-régression (i.e. vous exécutez vos tests de non-régression en utilisant la sortie de l'unité de test).

Capture d'écran de l'IHM du test runner :

guitestrunner.png

L'image montre que sur 10 tests exécutés, 6 tests ont échoué. Les exceptions EAssertionFailure indiquent que les assertions de test (voir en dessous) ne sont pas satisfaites i.e. le test a échoué. Les messages associés indiquent le résultat que le test attendait et le résultat obtenu.

Emploi dans FPC/Lazarus

Les tests FPCUnit sont utilisés dans le framework de test de base de données : Databases/fr#Ex.C3.A9cution_de_tests_de_bases_de_donn.C3.A9es_de_FPC.

Il y a aussi des tests pour le compilateur FPC/les paquet du coeur (core package), mais ceux-ci sont probablement antérieurs à la fpcunit et utilisent une approche plus simple.

Emploi

Il est plus simple d'utiliser Lazarus pour mettre en place un nouveau projet pour vous. En dessous, se trouvent quelques descriptions sur les procédures/méthodes à utiliser et pour quel usage.

Méthode Setup

Cette méthode est présente dans tous les tests FPCUnit. Il règle l'environnement de test avant que chaque test s'exécute, en d'autres termes, non seulement avant et après la suite complète des tests qui s'exécutent mais pour chaque test.. Vous pouvez utiliser ceci pour remplir une base de données avec des données de test.

Méthode Teardown

Cette procédure est présente das tous les tests FPCUnit et c'est l'inverse de la méthode Setup. Elle nettoie l'environnement de test après que chaque test se soit exécuté. Vous pouvez l'utiliser pour p.ex. effacer les données de test d'une base de données.

Décorateur de test : OneTimeSetup et OneTimeTearDown

Les procédures Setup et Teardown mentionnées au dessus sont exécutées une fois par test. Vous pouvez exécuter les procédures Setup et Teardown une fois par instance/exécution de votre test.

Pour faire ceci, utiliser OneTimeSetup et OneTimeTearDown et héritez depuis le "décorateur de test" TTestSetup et enregistrez-le, p.ex. :

uses
...
testdecorator
...
  TDBBasicsTestSetup = class(TTestSetup)
    protected
      procedure OneTimeSetup; override;
      procedure OneTimeTearDown; override;
    end; 
...
initialization
// make sure you register your test along with the decorator so it knows to run the setup/teardowns
  RegisterTestDecorator(TDBBasicsTestSetup, TTestDBBasics);

Tests

Vous écrivez vos propres tests comme des procédure publiées dans la classe de test (private, protected ou public ne marcheront pas). Vous pouvez utiliser AssertEquals etc. pour spécifier ce qui devrait être testé et donner un message adapté quand le test échoue.

Si vous voulez faire échouer un test, vous pouvez p.ex. utiliser :

if 5=0 then //ridiculous example but you understand what I mean. You can use other Assert* procedures to test equality much easier etc.
  AssertTrue('This part of the code should never have been reached in this test.',false);

Note : Il doit y avoir une meilleure façon de faire cela ...

Si le test échoue, une EAssertionFailedError sera levée avec le message que vous avez spécifié dans Assert*. De cette manière, vous pouvez ajouter des sous-tests et dire lequel des sous-tests échoue. Note : le test runner s'arrêtera au premier échec d'assertion donc les sous-tests subséquent ne seront pas exécutés. Si vous voulez toujours tout exécuter, découpez ces sous-tests en procédures de test séparées.

Au lieu des procédures Assert*, vous pouvez aussi utiliser les procédures Check* venant de DUnit (e.g. CheckEquals) qui donne des messages d'erreur plus descriptifs dans les résultats de test : ils incluent les valeurs attendues et actuelles.

L'ordre dans lequel les tests sont exécutés est celui dans lequel ils apparaissent dans la définition de la classe de test.

Exemple de test

  Ttestexport1 = class(Ttestcase)
...
  published
    procedure TestOutput;
...
procedure Ttestexport1.TestOutput;
const
  OutputFilename='output.csv';
begin
  TestDataSet.Close;
 
  if FileExists(OutputFilename) then DeleteFile(OutputFileName);
  TestDataset.FileName:=OutputFileName;
  TestDataset.Open;
  // Fill test data
  TestDataset.Append;
  TestDataset.FieldByName('ID').AsInteger := 1;
  // Data with quotes
  TestDataset.FieldByName('NAME').AsString := 'J"T"';
  TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  TestDataset.Post;
 
  TestDataset.Last;
  TestDataset.First;
  TestDataset.First;
  AssertEquals('Number of records in test dataset', 1, TestDataset.RecordCount);
  TestDataset.Close;
end;

Hiérarchie de tests

Dans des cas simples, vous (ou Lazarus) enregistreriez tous vos cas de test avec des appels tel que :

uses 
...
testregistry
...
initialization
  RegisterTest(Ttestexport1); //you pass the class name to register it for running

However, you can also create multiple layers to group your test cases if your project gets big:

initialization
  RegisterTest('WorldDominationApp.ExportCheesePlan',Ttestexport1); //The levels are separated by periods 
  RegisterTest('WorldDominationApp.Obsolete',TtestPinkysBrain1); //another category

Sortie

La test runner console peut sortir les résultat en XML (soit le format FPCUnit d'origine, ou un format plus avancé comme DUnit2 si vous utilisez l'unité xmltestreport), texte brut ou un format Latex (p.ex. utilisable pour des export pdf). Le test runner avec IHM sort les résultats en XML si demandé (en utilisant le même format XML xmltestreport).

Personnalisation de la sortie

Vous pouvez exécuter votre propre "écouter" (Listener) pour écouter les résultats de test et sortir les données de test de la manière que vous voulez. Créez un T*Listener qui implémente l'interface ITestListener. Il y a seulement 5 méthodes à implémenter.

Dans votre application test runner (i.e. une copie de fpctestconsole), ajoutez un objet écouteur ; enregistrez cet écouteur de test avec le framework de test (p.ex. votre test runner de console) via l'appel TestResult.AddListener() et il sera alimenté par les résultats des tests comme ils se produisent.

Testdbwriter

Un exemple d'écouteur personnalisé est l'écrivain de sortie de base de données (database output writer) disponible à https://bitbucket.org/reiniero/testdbwriter. Cet écrivain sauvera tous les résultats de tests vers une base de données, qui est optimisée pour recevoir une large quantité de résultats de tests (pratique pour l'utilisation sur un serveur d'intégration continue comme Jenkins ou pour l'importation/la consolidation de resultats de tests). Le référentiel mentionné contient un exemple qui exécute les résultat des tests du framework de test de base de données vers une autre base de données.

A faire : adapter ceci ; utiliser la nouvelle unité xml

Un exemple d'écouteur bonus disponible est TXMLResultsWriter dans l'unité xmlreporter dans <fpc>\packages\fcl-fpcunit\src\xmlreporter.pas.

todo: actuellement, dbtestframework semble utiliser une vieille méthode de sortie xml... Un exemple de test runner adapté qui utilise un écouteur supplémentaire peut être trouvé dans <fpc>\packages\fcl-db\tests\dbtestframework.pas, qui contient ce code pour sortir vers un écouteur personnalisé (un écrivain XML et un écrivain de condensé (digest writer) qui remplit la sortie dans une archive .tar, pratique pour traiter à distance) :

uses
 ...the rest of the units needed for test runners...
 fpcunit,...
 // the units with TXMLResultsWriter and TDigestResultsWriter
 testreport,DigestTestReport
...
Procedure LegacyOutput;
 
var
  FXMLResultsWriter: TXMLResultsWriter;
  FDigestResultsWriter: TDigestResultsWriter;
  testResult: TTestResult;
 
begin
  testResult := TTestResult.Create;
  FXMLResultsWriter := TXMLResultsWriter.Create;
  FDigestResultsWriter := TDigestResultsWriter.Create(nil);
  try
    testResult.AddListener(FXMLResultsWriter);
    testResult.AddListener(FDigestResultsWriter);
    // Set some properties specific for this results writer:
    FDigestResultsWriter.Comment:=dbtype;
    FDigestResultsWriter.Category:='DB';
    FDigestResultsWriter.RelSrcDir:='fcl-db';
    //WriteHeader is specific for this listener; it writes the header to an XML file
    //notice that it is not called for FDigestResultsWriter
    FXMLResultsWriter.WriteHeader;
    // This performs the actual test run, and the output will be processed by the listeners:
    GetTestRegistry.Run(testResult);
    // Likewise WriteResult is specific for this listener; it writes 
    FXMLResultsWriter.WriteResult(testResult);
  finally
    testResult.Free;
    FXMLResultsWriter.Free;
    FDigestResultsWriter.Free;
  end;
end;

Alternatives

  • DUnit2 - une énorme amélioration du DUnit initial. A l'origine écrit uniquement pour Delphi et qui est utilisé par l'énorme suite de tests d du framework tiOPF.
  • FPTest - une branche (fork) de DUnit2, et qui est spécialement mise au point pour l'emploi avec le compilateur Free Pascal.

Lazarus

Lazarus a des unités consoletestrunner et test runner avec IHM, qui peuvent être installée avec le paquet FPCUnitTestRunner. Cela vous aidera This will help you create and run your unit tests using a GUI (or console, if you want to). La consoletestrunner est compatible avec FPC donc vous n'avez pas besoin de Lazarus pour la compiler. La version Lazarus est légèremeent différente de celle de FPC (elle utilise p.ex. une sortie en UTF8 etc.).

L'IHM runner est plus facile à utiliser. Dans celle-ci, si vous voulez exécuter tous les tests, vous devez d'abord cliquer sur un élément de test avant que le bouton Run all tests ne soit activé.

GDB bug/fonctionnalité

Note (September 2012): a bug/undocumented feature in the debugger used by Lazarus/FPC (gdb) means that passing --all as run parameters has no effect. Passing this parameter can be useful when debugging console fpcunit test runners has no effect. Workaround: use -a. See bug [1]

Voir aussi