Avant de nous lancer dans notre refactoring, on peut encore aller plus loin sur nos tests afin d'améliorer encore notre confiance vis-à-vis de notre code base.
Pour ce faire on va écrire des tests de propriétés :
Quelles propriétés peut-on identifier à partir de notre Example Mapping ?
Ecrire des tests de propriétés en utilisant la librairie FsCheck
Démarrer une partie
On peut identifier des propriétés telles que :
forall(terrain contenant des galinettes, groupe de chasseurs avec chacun-e a minima 1 balle)
La partie de chasse doit démarrer avec succès
Ou encore :
forall(terrain sans galinettes, groupe de chasseurs avec au moins 1 chasseur sans balle)
La partie de chasse ne démarre pas car "pas de galinettes sur le terrain"
Cas passant
On commence par ajouter la dépendance sur FsCheck
dotnetaddpackageFsCheck.xUnit
On ajoute 1 test dans la classe DemarrerUnePartieDeChasse
[Property] // Annotation pour xUnitpublicPropertySur1TerrainAvecGalinettesEtAuMoins1ChasseurAvecTousDesBalles() =>Prop.ForAll(null, (terrain, chasseurs) =>true );
On doit travailler sur la génération d'un terrain valide
privatestaticArbitrary<(string nom,int nbGalinettes)> terrainGenerator()=> (from nom inArb.Generate<string>() // A minima 1 galinette sur le terrainfrom nbGalinette inGen.Choose(1,int.MaxValue)select (nom, nbGalinette)).ToArbitrary();
Ensuite, on travaille sur la manière de générer des chasseurs valides
privatestaticArbitrary<(string nom,int nbBalles)> chasseurGenerator()=> (from nom inArb.Generate<string>() // A minima 1 ballefrom nbBalles inGen.Choose(1,int.MaxValue)select (nom, nbBalles)).ToArbitrary();
On définit comment construire 1 groupe de chasseurs :
privatestaticArbitrary<FSharpList<(string nom,int nbBalles)>> groupeDeChasseursGenerator()=>// On définit le nombre de chasseurs dans le groupe [1; 1000] (from nbChasseurs inGen.Choose(1,1_000) // On utilise le nombre de chasseurs pour générer le bon nombre de chasseursselectchasseurGenerator().Generator.Sample(1, nbChasseurs)).ToArbitrary();
Cette propriété est complémentaire au test DemarrerUnePartieDeChasse.AvecPlusieursChasseurs qui valide la bonne instantiation de l'objet PartieDeChasse à partir d'un exemple.
Dans la propriété, on valide que la partie démarre sans se soucier de l'instantiation de la partie au sens du Domain.
Cas non passant
Concernant les cas non-passants, nous allons les remplacer par des tests de propriétés.
On commence par ce test :
[Fact]publicvoidSansChasseurs()=>ExecuteAndAssertThrow<ImpossibleDeDémarrerUnePartieSansChasseur>( s =>s.Demarrer(("Pitibon sur Sauldre",3),newList<(string,int)>()), p =>p.Should().BeNull() );
On le change en Property
[Property]publicPropertySansChasseursSurNimporteQuelTerrainRicheEnGalinette()=>Prop.ForAll( // On réutilise le générateur de terrains riches en galinettesterrainGenerator(), terrain => { // On va refactorer pour réutiliser cette logiquetry {PartieDeChasseService.Demarrer( terrain,newList<(string,int)>());returnfalse; }catch (ImpossibleDeDémarrerUnePartieSansChasseur) {returnRepository.SavedPartieDeChasse() ==null; } });
On crée une méthode qui va lancer l'action de manière safe et valider la lancement de l'exception