5 Архитектурных Тестов Необходимых Каждому .NET-Проекту. Начало
Каждый проект начинается с благих намерений. Вы согласовываете границы слоёв, соглашения об именовании, направление зависимостей. Через полгода кто-то переносит доменный сервис в проект инфраструктуры, обработчик получает имя не по соглашению или внутренний класс становится публичным, потому что это значение по умолчанию. Архитектурные тесты предотвращают это. Они превращают архитектурные правила в автоматизированные тесты, которые запускаются в CI. Вот архитектурные тесты, которые пригодятся каждому проекту.
ArchUnitNET - позволяет писать архитектурные правила, используя fluent API, и запускать их как обычные тесты. Для примера будем использовать xUnit, хотя поддерживаются и другие фреймворки:
dotnet add package TngTech.ArchUnitNET.xUnit
Нужен базовый класс, который загружает все сборки, которые мы хотим протестировать. Каждый слой получает «тип привязки» для получения ссылки на сборку во время компиляции:
public abstract class BaseTest
{
protected static readonly Assembly
DomainAssembly = typeof(User).Assembly;
protected static readonly Assembly
ApplicationAssembly = typeof(ICommand).Assembly;
// … аналогично остальные сборки
protected static readonly Architecture
Architecture = new ArchLoader()
.LoadAssemblies(
DomainAssembly,
ApplicationAssembly,
…)
.Build();
}
ArchLoader сканирует сборки и создает в памяти модель всех типов и их зависимостей.
Каждый тестовый класс наследует от BaseTest.
1. Тесты зависимостей слоёв
Внутренние слои в чистой архитектуре не должны ссылаться на внешние. В большинстве конфигураций чистой архитектуры ссылки на проекты уже предотвращают очевидные нарушения. Вы не можете добавить ссылку из приложения в инфраструктуру, т.к. инфраструктура уже ссылается на приложение, и компилятор не допустит циклических зависимостей.
Но тесты всё равно нужны, т.к. ссылки на проекты — не единственный способ проникновения зависимостей. NuGet, используемый в инфраструктуре, может содержать типы, которые проникают в приложение через транзитивные ссылки. Кто-то может реорганизовать решение и изменить граф ссылок проекта. Тесты — страховочная сетка и в то же время документальное подтверждение задуманной архитектуры.
public class LayerTests : BaseTest
{
private static readonly
IObjectProvider<IType> DomainLayer =
Types()
.That()
.ResideInAssembly(DomainAssembly)
.As("Domain layer");
private static readonly
IObjectProvider<IType> ApplicationLayer =
Types()
.That()
.ResideInAssembly(ApplicationAssembly)
.As("Application layer");
//…
[Fact]
public void Domain_ShouldNotDependOn_Application ()
{
Types().That().Are(DomainLayer).Should()
.NotDependOnAny(ApplicationLayer)
.Check(Architecture);
}
// … аналогично тесты остальных слоёв
}
Добавьте тесты для всех неверных направлений зависимостей.
Fluent API читается как английский язык: «Типы, находящиеся в доменном слое, не должны зависеть от каких-либо типов в прикладном слое». При возникновении нарушения тест точно указывает, какой тип от какого зависит.
Вы также можете расширить его. Например, добавить тесты, что определённые пространства имен внутри слоя не могут ссылаться друг на друга (например, Application.Orders не должны зависеть от Application.Users). Это может быть отлично для обеспечения вертикальной архитектуры, где каждая функция самодостаточна, или внутри модульного монолита, где модули не должны зависеть друг от друга.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/5-architecture-tests-you-should-add-to-your-dotnet-projects