Une communauté agile sur les environnements mainframe...

le 12/06/2009 par Hervé Vaujour
Tags: Product & Design

Prologue

Il existait Junit, Nunit, PHPUnit, RPGUnit,... mais pas de COBOLUnit. Donc il fallait s'y mettre, lancer les développements sur le sujet et... OUPS, j'ai oublié un point important je ne connais pas COBOL et je n'ai pas d'environnement z/OS!

Qu'à cela ne tienne, je m'arcqueboute, recherche sur le web, et pouf me voilà au volant d'un Ubuntu, le package OpenCobol est installé, il me reste à gérer le confort de conduite, j'opte pour le plug-in Cobol_plugins_3.4.0 sur Eclipse.

A présent la voiture est prête, je dois la conduire: c'est parti pour un cours de conduite accéléré: je télécharge le Cobol Guide d'IBM et je démarre l'engin. Ma culture open ne m'est pas d'une grande aide, mais bon après quelques itérations, inspirées de « Test-Driven Development By Example » de Kent Benk (fr.wikipedia.org/wiki/Test_Driven_Development), voilà la première version de COBOLUnit. Et pour vous présenter COBOLUnit rien de tel qu'un développement TDD (Test Driven Development) du célèbre jeu mastermind.

Pour ceux qui ne connaitraient pas le jeu du mastermind (http://fr.wikipedia.org/wiki/Mastermind):

Notre logiciel devra permettre d'initialiser une série de 4 chiffres de manière aléatoire (master).

Il demandera ensuite à un utilisateur de proposer une combinaison de 4 chiffres

Si les chiffres proposés sont ceux du master et qu'ils sont bien positionnés alors le programme retourne un pion noir par chiffre.

Exemples (de tests de recette) :

master: 1234, proposition: 1234 retourne 0 blanc et 4 noirs

master: 1256, proposition: 1234 retourne 0 blanc et 2 noirs

Si les chiffres proposés sont ceux du master mais pas dans  le bon ordre, le logiciel retourne un pion blanc par chiffre mal positionné.

Exemple:

master: 1222, proposition: 3331 retourne 1 blanc et 0 noir

master: 1299, proposition: 2188 retourne 2 blancs et 0 noir

master: 1234, proposition: 2124 retroune 2 blancs et 1 noir

MasterMind, COBOL et TDD

  • Etape 1: Il était une fois un test COBOL...

Création du programme de test en COBOL.

Ajout d'un test associé à la découverte des 4 chiffres dans le bon ordre; ce test s 'appellera « Test4Noirs ».

PROCEDURE DIVISION.

*Initialisation du moteur COBOLUnit

CALL "CBU_INIT".

*Initialisation de la suite de tests Mastermind dans le moteur COBOLUnit

MOVE "SuiteMasterMind" TO SuiteN.

MOVE "La suite des tests du mastermind" TO SuiteD.

CALL "CBU_ADD_SUITE" USING SuiteN SuiteD.

*Déclaration du test des 4 noirs et ajout du test au moteur COBOLUnit

MOVE "Test4Noirs" TO TestN.

MOVE "Test quand tout les pions ont été découverts" TO TestD.

CALL "CBU_ADD_TEST" USING TestN TestD.

CALL "CBU_RUN_SUITE".

STOP RUN.

END PROGRAM TestJeuCobol.

Lançons la suite de tests:

$ make test * 'Test4Noirs' running ... ..........................'Test4Noirs' Completed! (000 Asserts, 000 failed,001 error) _____________________________________________________ TEST SUITE FAILED!!! 001 test have been run (000 succeed, 000 failed, 001 in errors) (00 min:00 sec) _____________________________________________________

COBOLUnit nous informe qu'un test a été lancé et que ce test est en erreur; ce qui est normal car ce test a simplement été déclaré et non implémenté.

  • Etape 2: ...Il faut sauver le test du rouge...

Pour faire passer le test « Test4Noirs » au vert il nous faut l'implémenter:

********** Test des 4 couleurs bien placées

IDENTIFICATION DIVISION.

PROGRAM-ID. Test4Noirs.

ENVIRONMENT DIVISION.

CONFIGURATION SECTION.

DATA DIVISION.

WORKING-STORAGE SECTION.

[...]

PROCEDURE DIVISION.

* Initialisation des variables couleurs à trouver,

* des couleurs proposées, du résultat attendu

MOVE "1234" TO Coul-a-trouver.

MOVE "1234" TO Coul-essai.

MOVE "0b4n" TO Resultat-attendu.

* Initialisation du moteur masterMind avec les couleurs à trouver

CALL "MasterMind".

CALL "MSM-Set-Couleur-a-trouver" USING Coul-a-Trouver.

CALL "MSM-Test" USING Coul-Essai Resultat-retourne.

MOVE "Assert4N" TO assertName.

* Assertion

CALL "CBU_ASSERT_STR100_EQUALS" USING assertName

Resultat-retourne

Resultat-attendu.

END PROGRAM Test4Noirs.

Créons à présent le code du mastermind: 2 sous-programmes le composent:

Un premier qui assure l'initialisation du master:

************ Initialisation des couleurs

************ à trouver

IDENTIFICATION DIVISION.

PROGRAM-ID. MSM-Set-Couleur-a-trouver.

DATA DIVISION.

WORKING-STORAGE SECTION.

[...]

PROCEDURE DIVISION USING couleurs.

* J'initialise mon master avec les couleurs passé en paramètre

MOVE couleurs TO Couleurs-a-trouver.

EXIT PROGRAM.

END PROGRAM MSM-Set-Couleur-a-trouver.

Un second qui fait la comparaison entre la proposition du joueur et le master. Pour faire passer mon test, il me suffit de retourner le résultat attendu à savoir « 0b4n ».

"Uhuhu! C'est tricher!" criait le public en liesse. En effet, cette première itération ne sait rien faire d'autre que renvoyer "0b4n" !! C'est ça TDD: faire passer les tests au vert.

Implémlentons en dur le résultat attendu:

************* MSM-Test ************

* Test les couleurs présentées avec les couleurs à trouver

IDENTIFICATION DIVISION.

PROGRAM-ID. MSM-Test.

[...]

PROCEDURE DIVISION USING essai res.

MOVE "0b4n" TO res.

EXIT PROGRAM.

END PROGRAM MSM-Test.

La suite de test une fois lancé donne:

* 'Test4Noirs' running ...

Assert ('Assert4N') Succeed.

..........................'Test4Noirs' Completed! (001 Asserts, 000 failed,000 error)

_____________________________________________________

TEST SUITE SUCCEED!!!

001 test have been run (001 succeed, 000 failed, 000 in errors)

(00 min:00 sec)

_____________________________________________________

Le test passe obectif atteint!

  • Etape 3: … Un test c'est bien mais deux c'est mieux...

Ajoutons de nouveaux tests pour valider notre règle sur le calcul des pions noirs :

PROGRAM-ID. Test4Noirs.

[...]

PROCEDURE DIVISION.

* Assert 1

MOVE "1234" TO Coul-a-trouver.

MOVE "1234" TO Coul-essai.

MOVE "0b4n" TO Resultat-attendu.

CALL "MasterMind".

CALL "MSM-Set-Couleur-a-trouver" USING Coul-a-Trouver.

CALL "MSM-Test" USING Coul-Essai Resultat-retourne.

MOVE "Assert1234_1234" TO assertName.

CALL "CBU_ASSERT_STR100_EQUALS" USING assertName

Resultat-retourne

Resultat-attendu.

* Assert 2

MOVE "1111" TO Coul-a-trouver.

MOVE "1111" TO Coul-essai.

MOVE "0b4n" TO Resultat-attendu.

CALL "MasterMind".

CALL "MSM-Set-Couleur-a-trouver" USING Coul-a-Trouver.

CALL "MSM-Test" USING Coul-Essai Resultat-retourne.

MOVE "Assert1111_1111" TO assertName.

CALL "CBU_ASSERT_STR100_EQUALS" USING assertName

Resultat-retourne

Resultat-attendu.

END PROGRAM Test4Noirs.

********** Test de 3 couleurs bien placées et aucune mal placée

PROGRAM-ID. Test3Noirs.

[...]

PROCEDURE DIVISION.

* Assert 1

MOVE "1234" TO Coul-a-trouver.

MOVE "1235" TO Coul-essai.

MOVE "0b3n" TO Resultat-attendu.

CALL "MasterMind".

CALL "MSM-Set-Couleur-a-trouver" USING Coul-a-Trouver.

CALL "MSM-Test" USING Coul-Essai Resultat-retourne.

MOVE "Assert1234_1235" TO assertName.

CALL "CBU_ASSERT_STR100_EQUALS" USING assertName

Resultat-retourne

Resultat-attendu.

* Assert 2

MOVE "3234" TO Coul-a-trouver.

MOVE "4234" TO Coul-essai.

MOVE "0b3n" TO Resultat-attendu.

CALL "MasterMind".

CALL "MSM-Set-Couleur-a-trouver" USING Coul-a-Trouver.

CALL "MSM-Test" USING Coul-Essai Resultat-retourne.

MOVE "Assert3234_4234" TO assertName.

CALL "CBU_ASSERT_STR100_EQUALS" USING assertName

Resultat-retourne

Resultat-attendu.

END PROGRAM Test3Noirs.

L'exécution de la suite donne:

* 'Test4Noirs' running ...

Assert ('Assert1234_1234') Succeed.

Assert ('Assert1111_1111') Succeed.

..........................'Test4Noirs' Completed! (002 Asserts, 000 failed,000 error)

* 'Test3Noirs' running ...

Assert ('Assert1234_1235') Failed, expected: '0b3n', actual: '0b4n'

Assert ('Assert3234_4234') Failed, expected: '0b3n', actual: '0b4n'

..........................'Test3Noirs' Completed! (002 Asserts, 002 failed,000 error)

_____________________________________________________

TEST SUITE FAILED!!!

002 test have been run (001 succeed, 001 failed, 000 in errors)

(00 min:00 sec)

_____________________________________________________

Aïeuu!! la suite a échoué, COBOLUnit m'explique pourquoi en m'indiquant les résultats retournés (« actual ») par rapport aux attendus (« expected »).

Nous modifions donc le code pour faire passer les tests, cette fois-ci un peu d'algorithmie qui traite les noirs, mais pas encore les blancs … :

************* MSM-Test ************

* Test les couleurs présentes avec les couleurs à trouver

IDENTIFICATION DIVISION.

PROGRAM-ID. MSM-Test.

DATA DIVISION.

WORKING-STORAGE SECTION.

COPY MasterMindCOPY.

01 i PIC 9(1).

01 j PIC 9(1).

LINKAGE SECTION.

01 essai PIC 9(4).

01 res PIC X(4).

PROCEDURE DIVISION USING essai res.

* Parcours des couleurs du master

PERFORM VARYING i FROM 1 BY 1

UNTIL i>4

* Si une couleur proposée est la même que celle du master et à la même position

* J'ajoute un pion noir au résultat du test

IF Couleurs-a-trouver(i:1)=essai(i:1) THEN

ADD 1 TO Couleurs-placees

END-IF

END-PERFORM

* Concaténation du résultat

STRING

Couleurs-mal-placees

"b"

Couleurs-placees

"n"

INTO res.

EXIT PROGRAM.

END PROGRAM MSM-Test.

* 'Test4Noirs' running ...Assert ('Assert1234_1234') Succeed.Assert ('Assert1111_1111') Succeed...........................'Test4Noirs' Completed! (002 Asserts, 000 failed,000 error)* 'Test3Noirs' running ...Assert ('Assert1234_1235') Succeed.Assert ('Assert3234_4234') Succeed...........................'Test3Noirs' Completed! (002 Asserts, 000 failed,000 error)_____________________________________________________TEST SUITE SUCCEED!!!

002 test have been run (002 succeed, 000 failed, 000 in errors)

(00 min:00 sec)

_____________________________________________________

La suite est au vert, Implémentons le calcul des pions blancs... Non ce sera pour plus tard passons à l'épilogue!

Epilogue

Comme je vous l'ai dit en début d'article, je ne suis pas un expert gros systèmes ! Or qui de plus qualifiés que les utilisateurs mainframe pour évaluer cette première mouture de COBOLUnit, pour la faire évoluer, en un mot: pour le faire vivre ? Cet outil est pour moi le prétexte à un sujet plus ambitieux: Comment devenir ou faire de l'agile en environnement Mainframe?

Chaque équipe, chaque contexte projet, et chaque individu à des idées, des pratiques, des outils qui pourraient servir l'ensemble d'une communauté. A travers cette communauté je vous propose de mettre à disposition de tous le framework COBOLUnit, afin de le faire collectivement évoluer pour qu'il réponde à des besoins partagés. L'objectif est  de le distribuer en opensource (https://sourceforge.net/projects/cobolunit/).

Donc si vous souhaitez vivre cette aventure avec nous contactez moi directement (hvaujour@octo.com) afin que je vous communique les dates et lieu de nos prochains rendez-vous.

Nous pourrions d'ailleurs profiter d'une de ses sessions pour vous présenter la fin du mastermind développé en TDD sous COBOL! Qu'en pensez-vous?...