Comment appliquer des règles d’architecture en C#

Avec les tests unitaires, nous nous assurons que les blocs de code que nous écrivons font ce que nous voulions. Il existe quelques frameworks open source disponibles pour les tests unitaires des applications .NET, à savoir NUnit et xUnit.Net. Vous devez toujours intégrer les tests unitaires dans votre flux de travail de développement logiciel pour réduire ou éliminer les bogues dans vos applications.

Vous pouvez également utiliser des frameworks comme ArchUnit ou NetArchTest pour écrire des tests unitaires qui peuvent aider à appliquer les règles d’architecture. Inspiré d’ArchUnit pour Java, NetArchTest de Ben Morris est un framework léger qui peut être utilisé pour appliquer des règles architecturales dans .NET Framework ou .NET Core, ainsi que dans des projets .NET 6.

Cet article traite de l’importance de l’application des règles architecturales et de la manière d’utiliser NetArchTest pour y parvenir. Pour travailler avec les exemples de code fournis dans cet article, Visual Studio 2022 doit être installé sur votre système. Si vous n’en avez pas déjà une copie, vous pouvez télécharger Visual Studio 2022 ici.

La nécessité de faire respecter les règles architecturales

Il existe de nombreux frameworks et outils d’analyse de code statique pour vérifier la qualité du code dans .NET, .NET Core ou .NET 6. Deux outils populaires sont SonarQube et NDepend, pour commencer. L’analyse de code statique est également disponible dans le cadre de Visual Studio.

Cependant, certains de ces outils vous aident à maintenir des modèles de conception architecturale ou à appliquer des règles architecturales dans votre code source. Et si vous ne validez pas ou n’appliquez pas régulièrement ces règles, la conception ou l’architecture de votre application se dégradera avec le temps. Finalement, vous constaterez que la maintenance de la base de code est devenue une tâche ardue.

Alors que les outils d’analyse de code statique vous aident à valider ou à appliquer les meilleures pratiques génériques, vous pouvez tirer parti de NArchTest pour créer des tests unitaires qui appliquent des règles architecturales dans vos applications .NET, .NET Core et .NET 6. Cela inclut les conventions de conception, de dénomination et de dépendance des classes dans vos bases de code.

Vous pouvez utiliser NArchTest dans vos méthodes de test unitaire, puis intégrer ces méthodes de test dans le pipeline de construction et de publication afin que les règles d’architecture soient automatiquement validées à chaque enregistrement.

Créer un projet de test unitaire dans Visual Studio 2022

Commençons par créer un projet de test unitaire dans Visual Studio 2022 à l’aide du modèle de projet de test xUnit. Suivre ces étapes créera un nouveau projet de test unitaire dans Visual Studio 2022 :

  1. Lancez l’IDE Visual Studio 2022.
  2. Cliquez sur “Créer un nouveau projet”.
  3. Dans la fenêtre Créer un nouveau projet, sélectionnez Projet de test xUnit dans la liste des modèles qui s’affichent.
  4. Cliquez sur Suivant.
  5. Dans la fenêtre Configurer un nouveau projet, spécifiez le nom et l’emplacement du nouveau projet.
  6. Cochez éventuellement la case “Placer la solution et le projet dans le même répertoire” en fonction de vos préférences.
  7. Cliquez sur Suivant.
  8. Dans la fenêtre Informations supplémentaires qui s’ouvre, sélectionnez .NET 6.0 comme framework cible dans la liste déroulante en haut. Laissez le “Type d’authentification” sur “Aucun” (par défaut).
  9. Assurez-vous que les cases “Activer Docker”, “Configurer pour HTTPS” et “Activer la prise en charge de l’API ouverte” sont décochées car nous n’utiliserons aucune de ces fonctionnalités ici.
  10. Cliquez sur Créer.

Cela crée un nouveau projet xUnit dans Visual Studio 2022. Nous utilisons ce projet dans les sections suivantes de cet article.

Créer un projet de bibliothèque de classes dans Visual Studio 2022

Créons maintenant un projet de bibliothèque de classes dans Visual Studio 2022. En suivant ces étapes, vous créerez un nouveau projet de bibliothèque de classes dans Visual Studio 2022 :

  1. Lancez l’IDE Visual Studio 2022.
  2. Cliquez sur “Créer un nouveau projet”.
  3. Dans la fenêtre Créer un nouveau projet, sélectionnez Bibliothèque de classes dans la liste des modèles qui s’affichent.
  4. Cliquez sur Suivant.
  5. Dans la fenêtre Configurer un nouveau projet, spécifiez le nom et l’emplacement du nouveau projet.
  6. Cliquez sur Suivant.
  7. Dans la fenêtre Informations supplémentaires qui s’ouvre, sélectionnez .NET 6.0 comme framework cible dans la liste déroulante en haut.
  8. Cliquez sur Créer.

Cela crée un nouveau projet de bibliothèque de classes dans Visual Studio 2022. Nous utilisons ce projet dans les sections suivantes de cet article.

Créer des classes de modèles dans .NET 6

Supposons que le nom du projet de bibliothèque de classes est Core.Infrastructure. Dans la fenêtre Explorateur de solutions, sélectionnez ce projet, puis cliquez sur Ajouter -> Nouveau dossier pour ajouter un nouveau dossier de solution au projet. Les modèles doivent avoir le même nom que leur dossier de solution.

Créez maintenant une classe appelée BaseModel dans le dossier de la solution Models et collez le code suivant :

public abstract class BaseModel
    {
        public int Id { get; set; }
    }

Créez deux autres classes de modèles nommées Product et Customer. Chacune de ces deux classes doit étendre la classe BaseModel comme indiqué ci-dessous.

public class Product: BaseModel
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
public class Customer: BaseModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Créer des classes de service dans .NET 6

Dans le même projet, créez un autre dossier de solution et nommez-le Services. Dans ce dossier de solution, créez une interface appelée IBaseService et donnez-lui le code suivant :

public interface IBaseService
{
    public void Initialize();
}

La méthode Initialize doit être implémentée par toute classe qui implémente cette interface. Les classes ProductService et CustomerService implémentent l’interface IBaseService, comme illustré dans l’extrait de code suivant.

//ProductService.cs
using Core.Infrastructure.Models;
namespace Core.Infrastructure.Services
{
    public sealed class ProductService: IBaseService
    {
        public void Initialize()
        {
            //Write your implementation here
        }
        public List GetProducts()
        {
            return new List();
        }
    }
}

//CustomerService.cs
using Core.Infrastructure.Models;
namespace Core.Infrastructure.Services
{
    public sealed class CustomerService: IBaseService
    {
        public void Initialize()
        {
            //Write your implementation here
        }
        public List GetCustomers()
        {
            return new List();
        }
    }
}

Notez que pour cette implémentation simple, les méthodes Initialize des classes ProductService et CustomerService ont été laissées vides. Vous pouvez écrire votre propre implémentation pour cela.

Installez le package NuGet NetArchTest.Rules

Jusqu’ici tout va bien. Ajoutez maintenant le package NuGet NetArchTest.Rules à votre projet. Pour ce faire, sélectionnez le projet dans la fenêtre de l’Explorateur de solutions, cliquez avec le bouton droit et sélectionnez “Gérer les packages NuGet”. Dans la fenêtre NuGet Package Manager, recherchez et installez le package NetArchTest.Rules.

Vous pouvez également installer le package à partir de la console NuGet Package Manager en tapant la ligne ci-dessous.

PM> Install-Package NetArchTest.Rules

Écrire des tests unitaires d’architecture dans .NET 6

Enfin, vous devez écrire les tests unitaires de l’architecture pour vérifier que le code source à tester est conforme à vos standards. Notez que le terme normes est relatif ici et vous pouvez supposer que ces normes sont définies par vous.

La méthode de test suivante vérifie si vos classes de service ont un nom avec un suffixe de service.

[Fact]
public void ServiceClassesShouldHaveNameEndingWithService()
{
    var result = Types.InCurrentDomain()
                 .That().ResideInNamespace(("Core.Infrastructure.Services"))
                 .And().AreClasses()
                 .Should().HaveNameEndingWith("Service")
                 .GetResult();
    Assert.True(result.IsSuccessful);
}

Vous pourriez avoir une autre règle qui vérifie si toutes vos classes de service implémentent l’interface IBaseService. La procédure de test suivante illustre comment cela peut être réalisé.

[Fact]
public void ServiceClassesShouldImplementIBaseServiceInterface()
{
   var result = Types.InCurrentDomain()
                .That().ResideInNamespace(("Core.Infrastructure.Services"))
                .And().AreClasses()
                .Should().ImplementInterface(typeof(IBaseService))
                .GetResult();
   Assert.True(result.IsSuccessful);
}

Vous pouvez également avoir une règle qui vérifie si les classes de service sont publiques et non scellées. Une fois ces classes scellées, vous ne pouvez plus continuer à les renouveler.

[Fact]
public void ServiceClassesShouldBePublicAndNotSealed ()
{
    var result = Types.InCurrentDomain()
                .That().ResideInNamespace(("Core.Infrastructure.Services"))
                .Should().BePublic().And().NotBeSealed()
                .GetResult();
    Assert.True(result.IsSuccessful);
}

Si vous exécutez ces méthodes de test, vous devriez constater qu’elles réussissent toutes, c’est-à-dire qu’elles réussissent. Essayez de modifier le code et d’exécuter à nouveau les tests pour vérifier la conformité avec les règles décrites.

exemple de test netarch IDG

Tests unitaires NetArchTest en action.

N’oubliez pas que dans les nouvelles versions de C#, vous pouvez avoir une implémentation par défaut des membres dans une interface. Ainsi, si vous avez une interface implémentée par une ou plusieurs classes, vous pouvez écrire l’implémentation par défaut dans l’interface. Cela est vrai lorsque vous écrivez du code commun à toutes les implémentations de l’interface.

Copyright © 2022 IDG Communications, Inc.

Leave a Comment