A lightweight .NET library for writing architecture tests: verify layering, dependencies, naming conventions, and modular boundaries with a simple fluent API and extension methods.
Note: The Quick Start and usage examples below use xUnit for demonstration, but you can use Stella.Architecture.Tests with any .NET test framework (such as NUnit or MSTest).
Architecture tests help you:
- Enforce architectural boundaries between layers and modules
- Prevent unwanted dependencies from creeping into your codebase
- Catch violations early in the development proc√ess
- Document architectural decisions as executable tests
- ✅ Namespace isolation - Enforce isolated modules with no inbound/outbound dependencies
- ✅ Assembly dependencies - Prevent forbidden assembly references
- ✅ Type validation - Validate type characteristics (e.g., records)
- ✅ Fluent API - Readable and maintainable test syntax
- ✅ Comprehensive error reporting - Clear violation messages
- ✅ No dependencies - Lightweight library that integrates with any test framework
Install via NuGet Package Manager:
dotnet add package Stella.Architecture.TestsOr via Package Manager Console:
Install-Package Stella.Architecture.TestsEnsure a namespace doesn't depend on other parts of your assembly:
using Stella.Architecture.Tests;
using System.Reflection;
using Xunit;
public class ArchitectureTests
{
[Fact]
public void ShouldNotDependOnOtherLayers_WhenInDomainLayer()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithNamespaceNoOutboundDependencies("MyApp.Domain")
.ShouldBeValid();
}
}This test ensures that types in the MyApp.Domain namespace (and its child namespaces) do not reference any types from other namespaces in the same assembly.
Ensure a namespace is completely isolated with no dependencies to or from other namespaces (of your assembly):
[Fact]
public void ShouldBeIsolated_WhenInPluginNamespace()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithNamespaceIsolated("MyApp.Plugin")
.ShouldBeValid();
}Ensure all namespaces do not depend on this namespace (of your assembly):
[Fact]
public void ShouldNotBeReferenced_WhenInInternalNamespace()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithNamespaceNoInboundDependencies("MyApp.Internal")
.ShouldBeValid();
}Prevent your application from depending on specific assemblies:
[Fact]
public void ShouldNotDependOnLegacyLibraries_WhenInCoreAssembly()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithAssemblyForbiddenDependency("Newtonsoft") // Regex pattern
.ShouldBeValid();
}[Fact]
public void ShouldBeRecords_WhenImplementingIDto()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithType<IDto>(configure => configure.IsRecord())
.ShouldBeValid();
}
[Fact]
public void ShouldNotBeRecords_WhenImplementingIEntity()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithType<IEntity>(configure => configure.IsNotRecord())
.ShouldBeValid();
}Ensure that only specific types can depend on a target type:
[Fact]
public void ShouldOnlyBeUsedByServices_WhenDatabaseContext()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithDependencyUsedOnly<DatabaseContext>(typeof(IService))
.ShouldBeValid();
}
[Fact]
public void ShouldOnlyBeUsedByApprovedServices_WhenInternalApi()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithDependencyUsedOnly<InternalApi>(typeof(Service1), typeof(Service2))
.ShouldBeValid();
}[Fact]
public void ShouldTypeNameEndWithDto_WhenDto()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithType<IDto>(configure => configure.WithNameMatch(".*Dto$"))
.ShouldBeValid();
}Validate that types implementing an interface have namespaces starting with MyApp and ending with .Dtos :
[Fact]
public void DtoTypes_ShouldBeInDtoNamespace()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithType<IDto>(configure => configure.WithNamespaceMatch(@"^MyApp.*\.Dtos$"))
.ShouldBeValid();
}[Fact]
public void ShouldHaveMyAttribute_WhenImplementingIDto()
{
AssemblyArchitectureconfigure
.ForAssembly(Assembly.Load("MyApp"))
.WithType<IDto>(configure => configure.WithMethod(type => type.MethodA(),
configureMethod => configureMethod.WithRequiredAttribute(typeof(MyAttribute))))
.ShouldBeValid();
}