Contenu principal

Vérifier un algorithme MATLAB au moyen de tests reposant sur les exigences

Cet exemple indique comment vérifier un algorithme MATLAB® en créant des liens de vérification à partir des lignes de code MATLAB dans les fonctions et les tests vers les exigences. Cet exemple utilise un projet qui contient un algorithme permettant de calculer le chemin le plus court entre deux nœuds d’un graphe.

Ouvrez le projet ShortestPath.

openProject("ShortestPath");

Examiner les artefacts du projet

Le projet contient :

  • Des ensembles d’exigences pour les exigences fonctionnelles et de test, situés dans le dossier requirements

  • Un algorithme MATLAB situé dans le dossier src

  • Des tests unitaires MATLAB situés dans le dossier tests

  • Des liens entre les lignes de code MATLAB et les exigences, des fichiers .slmx stockés dans les dossiers src et tests

  • Des scripts permettant d’automatiser l’analyse du projet, situés dans le dossier scripts

Ouvrir l’ensemble d’exigences fonctionnelles

L’ensemble d’exigences shortest_path_func_reqs capture le comportement fonctionnel requis pour la fonction shortest_path. Les exigences décrivent le comportement nominal et le comportement attendu dans des conditions invalides, par exemple lorsque les entrées de la fonction ne sont pas valides. Ouvrez l’ensemble d’exigences dans le Requirements Editor.

funcReqs = slreq.open("shortest_path_func_reqs");

Utiliser la fonction du plus court chemin

La fonction shortest_path teste la validité des entrées de la fonction et utilise ensuite l’algorithme de Djikstra pour calculer le nombre d’arêtes du plus court chemin entre deux nœuds d’un graphique. Les entrées de la fonction sont une matrice d’adjacence qui représente un graphe, le nœud de départ et le nœud d’arrivée. Par exemple, intéressons-nous à cette matrice d’adjacence qui représente un graphe à six nœuds.

A = [0 1 0 0 1 0;
    1 0 1 0 0 0;
    0 1 0 1 0 0;
    0 0 1 0 1 1;
    1 0 0 1 0 0;
    0 0 0 1 0 0];

Créez un graphique à partir de la matrice et tracez-le.

G = graph(A);
plot(G,EdgeLabel=G.Edges.Weight)

Figure contains an axes object. The axes object contains an object of type graphplot.

Calculez le nombre d’arêtes du plus court chemin entre les nœuds 1 et 6.

pathLength = shortest_path(A,1,6)
pathLength = 3

Ouvrir l’ensemble d’exigences de test

L’ensemble d’exigences shortest_path_tests_reqs contient des exigences de test qui décrivent le comportement fonctionnel qui doit être testé par un cas de test. Les exigences de test sont dérivées des exigences fonctionnelles. Il existe des exigences de test pour le comportement nominal et pour les conditions invalides. Ouvrez l’ensemble d’exigences dans le Requirements Editor.

testReqs = slreq.open("shortest_path_tests_reqs");

Les tests unitaires MATLAB basés sur des classes dans graph_unit_tests implémentent les cas de test décrits dans shortest_path_tests_reqs. La classe contient des méthodes de test qui s’appuient sur les exigences de test de shortest_path_tests_reqs. La classe contient également la méthode verify_path_length, que les cas de test utilisent comme méthode de qualification pour vérifier que les résultats réels correspondent aux résultats attendus. La classe contient également des méthodes statiques qui créent des matrices d’adjacence pour les cas de test.

Afficher l’état de la vérification

Pour afficher l’état de la vérification, dans la barre d’outils du Requirements Editor, et plus précisément dans la section View, cliquez sur showColumns_16.pngColumns et sélectionnez Verification Status. Il manque des liens de vérification dans trois des exigences fonctionnelles et dans une exigence de test. L’état de la vérification est jaune pour chaque exigence, ce qui indique que les tests liés n’ont pas été exécutés.

missingVerification.png

Exécutez les tests et mettez à jour l’état de la vérification des ensembles d’exigences au moyen de la méthode runTests.

status1 = runTests(funcReqs);
Running graph_unit_tests
.......... ..
Done graph_unit_tests
__________
status2 = runTests(testReqs);
Running graph_unit_tests
.......... ...
Done graph_unit_tests
__________

L’état de la vérification est vert pour indiquer que les tests liés ont réussi. Toutefois, certaines exigences ne sont pas liées à des tests.

Identifier les manques du projet en matière de traçabilité

Les exigences fonctionnelles et de test sont liées aux lignes de code des fichiers shortest_path et graph_unit_tests, mais la traçabilité n’est pas complète. Utilisez une matrice de traçabilité pour identifier les exigences qui ne sont pas liées à des tests et pour créer des liens et ainsi rendre les exigences entièrement traçables.

Trouver les liens manquants avec une matrice de traçabilité

Créez une matrice de traçabilité pour les deux ensembles d’exigences avec les exigences en haut et les tests unitaires à gauche. Pour plus d’informations sur les matrices de traçabilité, consultez Track Requirement Links with a Traceability Matrix.

mtxOpts = slreq.getTraceabilityMatrixOptions;
mtxOpts.topArtifacts = {'shortest_path_func_reqs.slreqx','shortest_path_tests_reqs.slreqx'};
mtxOpts.leftArtifacts = {'graph_unit_tests'};
slreq.generateTraceabilityMatrix(mtxOpts)

Dans Filter Panel, dans la section Top, filtrez la matrice de manière à n’afficher que les exigences fonctionnelles non liées à des tests en cliquant sur :

  • Top > Link > Missing Links

  • Top > Type > Functional

Dans la section Left, affichez uniquement les fonctions de test du fichier graph_unit_tests en cliquant sur :

  • Left > Type > Function

  • Left > Attributes > Test

Dans la barre d’outils, cliquez sur Highlight Missing Links.

missingLinksTRMX.png

La fenêtre Traceability Matrix présente les trois exigences fonctionnelles et l’exigence de test dépourvues de liens de vérification.

Créer des liens de vérification pour les exigences

L’exigence de test 2.1.3, Test for a graph that is a tree, n’est liée à aucun test. Une arborescence est un graphe dans lequel deux nœuds quelconques ne sont connectés que par un seul chemin.

Le cas de test check_invalid_start_1 teste une arborescence en utilisant la méthode statique graph_straight_seq afin de créer la matrice d’adjacence. Utilisez la méthode graph_straight_seq pour afficher l’arborescence.

A = graph_unit_tests.graph_straight_seq;
G = graph(A);
plot(G,EdgeLabel=G.Edges.Weight)

Figure contains an axes object. The axes object contains an object of type graphplot.

Créez un lien entre l’exigence Test for a graph that is a tree et le cas de test check_invalid_start_1 en utilisant la matrice de traçabilité générée précédemment.

slreq.generateTraceabilityMatrix(mtxOpts)

Cliquez sur la cellule correspondant à l’exigence et au test, et sélectionnez Create. Dans la boîte de dialogue Create Link, cliquez sur Create.

createTestLink.png

Mettez à jour l’état de la vérification dans le Requirements Editor en exécutant les tests liés aux exigences de test. Le test check_invalid_start_1 vérifie l’exigence Test for a graph that is a tree.

status3 = runTests(testReqs);
Running graph_unit_tests
.......... ...
Done graph_unit_tests
__________

En outre, trois exigences fonctionnelles ne sont pas liées à des tests :

  • Exigence 2.2.1 : Returns -9 for invalid adjacency matrices

  • Exigence 2.2.2 : Returns -19 if the start node is encoded incorrectly

  • Exigence 2.2.3 : Returns -29 if end node is encoded incorrectly

Ces exigences présentent un manque de traçabilité. Vous ne pouvez pas combler ce manque en créant des liens vers des tests. En effet, il n’existe pas de tests permettant de vérifier ces exigences.

Corriger les manques de couverture et de traçabilité en créant des tests

Les trois exigences fonctionnelles dépourvues de liens vers des tests présentent des liens vers des lignes de code dans la fonction shortest_path. Exécutez les tests avec couverture pour déterminer si les lignes de code de la fonction shortest_path sont couvertes par les tests.

Exécuter des tests avec couverture

Utilisez le script RunTestsWithCoverage pour exécuter les tests avec couverture des fonctions et des instructions, et ainsi afficher la couverture dans un rapport. Pour plus d’informations, consultez Collect Statement and Function Coverage Metrics for MATLAB Source Code.

RunTestsWithCoverage
Running graph_unit_tests
.......... ....
Done graph_unit_tests
__________

MATLAB code coverage report has been saved to:
 C:\Users\ahoward\AppData\Local\Temp\tpc3b346ea_31dd_409d_be4c_5e787898bf8f\index.html

Ouvrez le rapport de couverture. Les instructions de code d’erreur des lignes 20, 25 et 30 ne sont pas couvertes par les tests.

missingCoverage.png

Remarque : le manque de couverture pour ces lignes de code et le manque de traçabilité pour les exigences 2.2.1, 2.2.2 et 2.2.3 concernent les mêmes codes d’erreur. Vous pouvez combler simultanément les manques de couverture et de traçabilité en créant des tests pour ces lignes de code et en établissant des liens avec les exigences.

Améliorer la couverture en créant de nouveaux tests

Créez des tests qui améliorent la couverture des tests et vérifient les exigences 2.2.1, 2.2.2 et 2.2.2. Ouvrez le fichier de test graph_unit_tests.

open("graph_unit_tests.m");

Ces fonctions testent les trois codes d’erreur. Copiez et collez le code à la ligne 4, dans la section des méthodes de test du fichier graph_unit_tests, puis enregistrez le fichier.

function check_invalid_nonsquare(testCase)
    adjMatrix = zeros(2,3);
    startIdx = 1;
    endIdx = 1;
    expOut = -9;
    verify_path_length(testCase, adjMatrix, startIdx, endIdx, expOut, ...
        'Graph is not square');
end

function check_invalid_entry(testCase)
    adjMatrix = 2*ones(4,4);
    startIdx = 1;
    endIdx = 1;
    expOut = -9;
    verify_path_length(testCase, adjMatrix, startIdx, endIdx, expOut, ...
        'Adjacency matrix is not valid');
end

function check_invalid_noninteger_startnode(testCase)
    adjMatrix = zeros(4,4);
    startIdx = 1.2;
    endIdx = 1;
    expOut = -19;
    verify_path_length(testCase, adjMatrix, startIdx, endIdx, expOut, ...
        'Start node is not an integer');
end

function check_invalid_noninteger_endnode(testCase)
    adjMatrix = zeros(4,4);
    startIdx = 1;
    endIdx = 2.2;
    expOut = -29;
    verify_path_length(testCase, adjMatrix, startIdx, endIdx, expOut, ...
        'End node is not an integer');
end

Réexécutez les tests avec couverture et ouvrez le rapport de couverture.

RunTestsWithCoverage
Running graph_unit_tests
.......... ....
Done graph_unit_tests
__________

MATLAB code coverage report has been saved to:
 C:\Users\ahoward\AppData\Local\Temp\tpd094de61_604e_45b4_8b53_767a6f4719cb\index.html

Désormais, les tests couvrent les instructions de code d’erreur.

improvedCoverage.png

Toutefois, la ligne 97 comporte une instruction qui n’est pas couverte par les tests. Les conditions qui exigent que les tests couvrent l’instruction de la ligne 97 entraînent également l’exécution de return à la ligne 87. Autrement dit, l’instruction de la ligne 97 n’est pas accessible et il s’agit d’une logique morte.

deadLogic.png

Combler les manques de traçabilité des exigences

Régénérez la matrice de traçabilité, appliquez les mêmes filtres que précédemment, puis cliquez surHighlight Missing Links dans la barre d’outils.

slreq.generateTraceabilityMatrix(mtxOpts)
  • Top > Link > Missing Links

  • Top > Type > Functional

  • Left > Type > Function

  • Left > Attributes > Test

Créez des liens entre les exigences du code d’erreur et les nouveaux tests.

createLinksImproveCoverage.png

Mettez à jour l’état de la vérification dans le Requirements Editor en réexécutant les tests liés aux deux ensembles d’exigences.

status4 = runTests(funcReqs);
Running graph_unit_tests
.......... ..
Done graph_unit_tests
__________
status5 = runTests(testReqs);
Running graph_unit_tests
.......... ...
Done graph_unit_tests
__________

Toutes les exigences présentent des liens vers des tests et tous les tests réussissent.

updatedVerificationStatus.png

Suivre les exigences dans le code généré

Utilisez Embedded Coder® pour générer du code à partir de l’algorithme shortest_path et incluez des commentaires d’exigences qui vous permettent de tracer les exigences dans le code généré. Pour plus d’informations, consultez Requirements Traceability for Code Generated from MATLAB Code.

Créez un objet de configuration de code pour générer du code avec un type de construction LIB.

cfg = coder.config("lib","ecoder",true);

Activez le paramètre de configuration du code pour inclure des commentaires sur les exigences dans le code généré.

cfg.ReqsInCode = true;

Utilisez coder.typeof (MATLAB Coder) pour définir un double tableau de taille variable présentant une taille maximale de 100x100 et un double scalaire à utiliser comme entrées dans le code généré.

mtxType = coder.typeof(ones(100,100),[],1);
scalarDblType = coder.typeof(1);

Générez du code C à partir de l’algorithme shortest_path avec les paramètres de configuration du code et les types d’entrée spécifiés. Créez un rapport de génération de code et lancez le rapport.

codegen shortest_path -config cfg -args {mtxType, scalarDblType, scalarDblType} -launchreport
Code generation successful: View report

codegen-report-requirements-comments.png

Le fichier shortest_path.c contient des commentaires avec le résumé de l’exigence liée, le chemin d’accès complet au fichier shortest_path.m et les lignes de code liées.

Voir aussi

| (MATLAB Coder) | (MATLAB Coder)

Rubriques