On peut spécifier à dotnet de traiter les warnings comme erreur de compilation via la ligne de commande suivante :
dotnetbuild-warnaserror
On a dès lors 7 erreurs de compilation :
Le problème ici, c'est que cette ligne de commande n'est pas partagée entre tous les devs travaillant sur le système :
IDE Build
Continuous Integration
Ainsi, la volonté de traiter tous les warnings comme des erreurs peut être facilement "oubliée" en compilant via son IDE ou en omettant de spécifier l'argument passer ici.
On va dès lors privilégier l'option ci-dessous qui permet de partager la configuration de compilation quelque soit la manière de faire.
Configurer nos projets
Pour configurer chaque projet on peut éditer le fichier csproj à la main et y ajouter :
On doit maintenant résoudre les 7 erreurs. On commence par le projet du code de production Bouchonnois.
Bouchonnois
Nous avons plusieurs options pour résoudre les erreurs de compilation comme présenté par Rider :
Ici, nous allons privilégier l'initialisation de la propriété par le constructeur.
Cela permet de :
Renforcer l'encapsulation
Si nous n'avons pas besoin d'exposer le champ Nom de manière public nous pourrons le rendre private
Forcer / exposer ce qui est requis lors de l'instantiation de nos objets
Renforcer les règles métiers
Initialiser des valeurs par défaut (Status par exemple) depuis le constructeur
Ne plus "diluer" cette responsabilité dans le système
publicclassTerrain{publicTerrain(string nom) { Nom = nom; }publicstring Nom { get; init; }publicint NbGalinettes { get; set; }}
On va pouvoir se laisser driver par notre compilateur à chaque modification.
On va également pouvoir renforcer l'encapsulation et rendre des champs init-only :
On va améliorer la qualité du code en même temps :
publicPartieDeChasse(Guid id, Terrain terrain){ Id = id; // La liste de chasseurs ne sera jamais null Chasseurs =newList<Chasseur>(); Terrain = terrain; // Initialiser le Status depuis le constructeur afin qu'à l'instanciation le status soit le bon Status =PartieStatus.EnCours; // La liste d'events ne sera jamais null Events =newList<Event>();}
Fixer les tests
Après les modifications sur le projet de production, on doit fixer les tests -> l'instantiation des objets du Domain.
[Fact]publicvoid QuandLaPartieVientDeDémarrer(){var id =Guid.NewGuid();var repository =newPartieDeChasseRepositoryForTests();var service =newPartieDeChasseService(repository, () =>DateTime.Now); // Changer l'instantiationrepository.Add(newPartieDeChasse { Id = id, Chasseurs =newList<Chasseur> {new() {Nom ="Dédé", BallesRestantes =20},new() {Nom ="Bernard", BallesRestantes =8},new() {Nom ="Robert", BallesRestantes =12, NbGalinettes =2}, }, Terrain =newTerrain { Nom ="Pitibon sur Sauldre", NbGalinettes =3 }, Status =PartieStatus.EnCours, Events =newList<Event> {new(newDateTime(2024,4,25,9,0,12),"La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)") } });var status =service.ConsulterStatus(id);status.Should() .Be("09:00 - La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)" );}
En essayant de corriger les tests on se rend compte qu'on a besoin d'un nouveau constructeur... ou d'une manière simple d'ajouter des chasseurs / events dans la PartieDeChasse. Pour le moment et afin de pouvoir compiler, nous allons créer un nouveau constructeur.
[Fact]publicvoid QuandLaPartieVientDeDémarrer(){var id =Guid.NewGuid();var repository =newPartieDeChasseRepositoryForTests();var service =newPartieDeChasseService(repository, () =>DateTime.Now);repository.Add(newPartieDeChasse(id,newTerrain("Pitibon sur Sauldre"){ NbGalinettes =3 },newList<Chasseur> {new("Dédé") {BallesRestantes =20},new("Bernard") {BallesRestantes =8},new("Robert") {BallesRestantes =12, NbGalinettes =2}, },newList<Event> {new(newDateTime(2024,4,25,9,0,12),"La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)") }));var status =service.ConsulterStatus(id);status.Should() .Be("09:00 - La partie de chasse commence à Pitibon sur Sauldre avec Dédé (20 balles), Bernard (8 balles), Robert (12 balles)" );}
A la fin notre classe PartieDeChasse ressemble à celà:
usingBouchonnois.Service;namespaceBouchonnois.Domain{publicclassPartieDeChasse {publicGuid Id { get; }publicList<Chasseur> Chasseurs { get; }publicTerrain Terrain { get; } // Toujours in problème d'encapsulation icipublicPartieStatus Status { get; set; }publicList<Event> Events { get; init; }publicPartieDeChasse(Guid id,Terrain terrain) { Id = id; Chasseurs =newList<Chasseur>(); Terrain = terrain; Status =PartieStatus.EnCours; Events =newList<Event>(); } // Nous avons ajouté 3 constructeurs pour les tests...publicPartieDeChasse(Guid id,Terrain terrain,List<Chasseur> chasseurs):this(id, terrain) { Chasseurs = chasseurs; }publicPartieDeChasse(Guid id,Terrain terrain,List<Chasseur> chasseurs,List<Event> events):this(id, terrain, chasseurs) { Events = events; }publicPartieDeChasse(Guid id,Terrain terrain,List<Chasseur> chasseurs,PartieStatus status):this(id, terrain, chasseurs) { Status = status; } }}