Ecrire des tests d'architecture en utilisant la librairie ArchUnit
Step 7 : Tests d'architecture
Pour aller plus vite, voici une classe contenant des extensions facilitant l'écriture et le lancement de tels tests :
Inward Dependencies
On va valider le sens des dépendances en ajoutant une nouvelle classe de tests
On définit les couches de notre onion :
Domain Model
On peut alors écrire une première règle pour notre Domain Model :
Celle-ci échoue :
Failing Arch Test
La classe Terrain se trouve dans l'Application Services alors qu'elle est une entité à part entière du Domain...
On corrige cela en déplaçant la classe :
Move class
Règle de l'Application Services
On en profite pour implémenter une règle sur l'Application Service :
Quid de l'infrastructure ?
Pour le moment nous n'avons qu'une interface de Repository (Un Port) au sein du namespace Infrastructure.
Est-ce que cela fait du sens au regard de la règle de dépendance ?
Nous allons déplacer ce port dans le Domain.
Nous pouvons tout de même implémenter une règle spécifiant que les items présents dans le namespace Repository doit implémenter l'interface IPartieDeChasseRepository :
Règles d'équipe
On peut ajouter certaines règles d'équipe du genre :
Toutes les interfaces doivent commencer par I
Une méthode commençant par Get doit retourner quelque chose
using ArchUnitNET.Fluent;
using ArchUnitNET.Fluent.Syntax.Elements.Types;
using ArchUnitNET.Loader;
using ArchUnitNET.xUnit;
using Bouchonnois.Service;
using static ArchUnitNET.Fluent.ArchRuleDefinition;
namespace Bouchonnois.Tests.Architecture
{
public static class ArchUnitExtensions
{
private static readonly ArchUnitNET.Domain.Architecture Architecture =
new ArchLoader()
.LoadAssemblies(typeof(PartieDeChasseService).Assembly)
.Build();
public static GivenTypesConjunction TypesInAssembly() =>
Types().That().Are(Architecture.Types);
public static void Check(this IArchRule rule) => rule.Check(Architecture);
}
// Exemple de test
public class Guidelines
{
private static GivenMethodMembersThat Methods() => MethodMembers().That().AreNoConstructors().And();
[Fact]
public void NoGetMethodShouldReturnVoid() =>
Methods()
.HaveName("Get[A-Z].*", useRegularExpressions: true).Should()
.NotHaveReturnType(typeof(void))
.Check();
}
}
public class ArchitectureRules
{
[Fact]
public void ApplicationServicesRules() =>
{
// Les classes dans l'Application Services ne devraient pas dépendre de classes dans Infrastructure
}
[Fact]
public void InfrastructureRules()
{
// Quelles sont les classes de l'infrastructure ?
// Que devrions nous faire de ce qui est contenu dans Infra ?
}
[Fact]
public void DomainModelRules()
{
// Les classes dans Domain ne devraient pas dépendre de classes dans Infrastructure ou Application Services
}
}