Une communauté agile sur les environnements mainframe...
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?...