ArchitectureAssert Class
The assertions on the dependencies of the types of an ArchitectureModel, available as Assert.Architecture. Each assertion throws an AssertionException that lists every type that breaks it, with the statements that cause it. To check the names or the shape of types, use Assert.All with the members of TypeElement.
public sealed class ArchitectureAssertRemarks
Each assertion fails when the types to check are empty, so that a typo in a namespace does not make it pass silently. Add your own assertions with an extension block on ArchitectureAssert.
Methods
| Name | Description |
|---|---|
| DependsOnlyOn(IEnumerable<TypeElement>, IEnumerable<TypeElement>, string?, string?, string?) | Asserts that the types only use the allowed types and each other. Only the types of the loaded assemblies are checked: use the overload that takes a predicate to also check the types of .NET and of the packages. |
| DependsOnlyOn(IEnumerable<TypeElement>, Func<TypeReference, bool>, string?, string?, string?) | Asserts that the types only use each other and the types that match a predicate, including the types defined outside the loaded assemblies. |
| DoesNotAccessMember(IEnumerable<TypeElement>, Type, string, string?, string?) | Asserts that the types do not use a member of type: call a method or a constructor, read or write a field, a property or an event. |
| DoesNotAccessMember<T>(IEnumerable<TypeElement>, string, string?, string?) | Asserts that the types do not use a member of T: call a method or a constructor, read or write a field, a property or an event. |
| DoesNotDependOn(IEnumerable<TypeElement>, IEnumerable<TypeElement>, string?, string?, string?) | Asserts that the types do not use any of the forbidden types. The dependencies between the checked types themselves are ignored. |
| DoesNotDependOn(IEnumerable<TypeElement>, Func<TypeReference, bool>, string?, string?, string?) | Asserts that the types do not use any type that matches a predicate. Unlike the other overloads, the predicate also sees the types defined outside the loaded assemblies. |
| DoesNotDependOn(IEnumerable<TypeElement>, Type, string?, string?) | Asserts that the types do not use type. |
| DoesNotDependOn<T>(IEnumerable<TypeElement>, string?, string?) | Asserts that the types do not use T. |
| DoesNotDependOnEachOther(IEnumerable<IGrouping<string, TypeElement>>, string?, string?) | Asserts that the slices do not use each other at all. Each type that uses another slice is reported. |
| DoesNotHaveCycles(IEnumerable<IGrouping<string, TypeElement>>, string?, string?) | Asserts that the slices do not depend on each other in a cycle (Orders → Billing → Orders). A slice may use another one. Each group of slices that depend on each other is reported once, with one of the shortest cycles and the dependencies that make it. |
DependsOnlyOn overloads
DependsOnlyOn(IEnumerable<TypeElement>, IEnumerable<TypeElement>, string?, string?, string?)
ArchitectureAssert.csAsserts that the types only use the allowed types and each other. Only the types of the loaded assemblies are checked: use the overload that takes a predicate to also check the types of .NET and of the packages.
public void DependsOnlyOn(IEnumerable<TypeElement> types, IEnumerable<TypeElement> allowedTypes, string? message = null, string? typesExpression = null, string? allowedTypesExpression = null)Parameters
typesIEnumerable<TypeElement>- The types to check.
allowedTypesIEnumerable<TypeElement>- The types that may be used.
messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types. allowedTypesExpressionstring?- The expression of
allowedTypes.
Exceptions
AssertionException- A type uses a type that is not allowed, or
typesis empty.
DependsOnlyOn(IEnumerable<TypeElement>, Func<TypeReference, bool>, string?, string?, string?)
ArchitectureAssert.csAsserts that the types only use each other and the types that match a predicate, including the types defined outside the loaded assemblies.
public void DependsOnlyOn(IEnumerable<TypeElement> types, Func<TypeReference, bool> predicate, string? message = null, string? typesExpression = null, string? predicateExpression = null)Parameters
typesIEnumerable<TypeElement>- The types to check.
predicateFunc<TypeReference, bool>- Returns
truefor an allowed type, such ast => t.IsInNamespaceOrChildren("System"). messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types. predicateExpressionstring?- The expression of
predicate.
Exceptions
AssertionException- A type uses a type that is not allowed, or
typesis empty.
Example
var architecture = ArchitectureModel.FromAssemblyContaining<Order>();
var domain = architecture.Types.Where(t => t.IsInNamespaceOrChildren("SampleApp.Domain"));
// The types of the domain may use each other and the types of .NET, nothing else
Assert.Architecture.DependsOnlyOn(domain, t => t.IsInNamespaceOrChildren("System"));DoesNotAccessMember overloads
DoesNotAccessMember(IEnumerable<TypeElement>, Type, string, string?, string?)
ArchitectureAssert.csAsserts that the types do not use a member of type: call a method or a constructor, read or write a field, a property or an event.
public void DoesNotAccessMember(IEnumerable<TypeElement> types, Type type, string memberName, string? message = null, string? typesExpression = null)Parameters
typesIEnumerable<TypeElement>- The types to check.
typeType- The type that declares the member.
memberNamestring- The name of the member (
nameof(DateTime.Now)), or.ctorfor the constructors. messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types.
Exceptions
AssertionException- A type uses the member, or
typesis empty.
DoesNotAccessMember<T>(IEnumerable<TypeElement>, string, string?, string?)
ArchitectureAssert.csAsserts that the types do not use a member of T: call a method or a constructor, read or write a field, a property or an event.
public void DoesNotAccessMember<T>(IEnumerable<TypeElement> types, string memberName, string? message = null, string? typesExpression = null)Type parameters
T- The type that declares the member.
Parameters
typesIEnumerable<TypeElement>- The types to check.
memberNamestring- The name of the member (
nameof(DateTime.Now)), or.ctorfor the constructors. messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types.
Exceptions
AssertionException- A type uses the member, or
typesis empty.
Example
var architecture = ArchitectureModel.FromAssemblyContaining<Order>();
var types = architecture.Types.Where(t => t.IsInNamespaceOrChildren("SampleApp"));
Assert.Architecture.DoesNotAccessMember<DateTime>(types, "Now", "the current time comes from TimeProvider");
Assert.Architecture.DoesNotAccessMember<DateTime>(types, nameof(DateTime.UtcNow), "the current time comes from TimeProvider");DoesNotDependOn overloads
DoesNotDependOn(IEnumerable<TypeElement>, IEnumerable<TypeElement>, string?, string?, string?)
ArchitectureAssert.csAsserts that the types do not use any of the forbidden types. The dependencies between the checked types themselves are ignored.
public void DoesNotDependOn(IEnumerable<TypeElement> types, IEnumerable<TypeElement> forbiddenTypes, string? message = null, string? typesExpression = null, string? forbiddenTypesExpression = null)Parameters
typesIEnumerable<TypeElement>- The types to check.
forbiddenTypesIEnumerable<TypeElement>- The types that must not be used, such as the types of another layer.
messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types. forbiddenTypesExpressionstring?- The expression of
forbiddenTypes.
Exceptions
AssertionException- A type uses a forbidden type, or
typesorforbiddenTypesis empty.
Example
var architecture = ArchitectureModel.FromAssemblyContaining<Order>();
var domain = architecture.Types.Where(t => t.IsInNamespaceOrChildren("SampleApp.Domain"));
var infrastructure = architecture.Types.Where(t => t.IsInNamespaceOrChildren("SampleApp.Infrastructure"));
Assert.Architecture.DoesNotDependOn(domain, infrastructure, "the domain stays persistence-ignorant");
Assert.Architecture.DoesNotDependOn(domain, t => t.IsInNamespaceOrChildren("Microsoft.EntityFrameworkCore"));
Assert.Architecture.DoesNotDependOn<HttpClient>(domain);DoesNotDependOn(IEnumerable<TypeElement>, Func<TypeReference, bool>, string?, string?, string?)
ArchitectureAssert.csAsserts that the types do not use any type that matches a predicate. Unlike the other overloads, the predicate also sees the types defined outside the loaded assemblies.
public void DoesNotDependOn(IEnumerable<TypeElement> types, Func<TypeReference, bool> predicate, string? message = null, string? typesExpression = null, string? predicateExpression = null)Parameters
typesIEnumerable<TypeElement>- The types to check.
predicateFunc<TypeReference, bool>- Returns
truefor a forbidden type, such ast => t.IsInNamespaceOrChildren("Microsoft.EntityFrameworkCore"). messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types. predicateExpressionstring?- The expression of
predicate.
Exceptions
AssertionException- A type uses a forbidden type, or
typesis empty.
DoesNotDependOn(IEnumerable<TypeElement>, Type, string?, string?)
ArchitectureAssert.csAsserts that the types do not use type.
public void DoesNotDependOn(IEnumerable<TypeElement> types, Type type, string? message = null, string? typesExpression = null)Parameters
typesIEnumerable<TypeElement>- The types to check.
typeType- The forbidden type, or a generic type definition (
typeof(List<>)) to forbid all its instantiations. messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types.
Exceptions
AssertionException- A type uses
type, ortypesis empty.
DoesNotDependOn<T>(IEnumerable<TypeElement>, string?, string?)
ArchitectureAssert.csAsserts that the types do not use T.
public void DoesNotDependOn<T>(IEnumerable<TypeElement> types, string? message = null, string? typesExpression = null)Type parameters
T- The forbidden type.
Parameters
typesIEnumerable<TypeElement>- The types to check.
messagestring?- The message that describes the failure.
typesExpressionstring?- The expression of
types.
Exceptions
AssertionException- A type uses
T, ortypesis empty.
DoesNotDependOnEachOther(IEnumerable<IGrouping<string, TypeElement>>, string?, string?)
ArchitectureAssert.csAsserts that the slices do not use each other at all. Each type that uses another slice is reported.
public void DoesNotDependOnEachOther(IEnumerable<IGrouping<string, TypeElement>> slices, string? message = null, string? slicesExpression = null)Parameters
slicesIEnumerable<IGrouping<string, TypeElement>>- The slices, such as the result of
TypeElementExtensions.SliceByNamespaceor ofGroupBy. A type must not be in several slices. messagestring?- The message that describes the failure.
slicesExpressionstring?- The expression of
slices.
Exceptions
AssertionException- A type uses another slice, or
slicesis empty. ArgumentException- Two slices have the same name, or a type is in several slices.
DoesNotHaveCycles(IEnumerable<IGrouping<string, TypeElement>>, string?, string?)
ArchitectureAssert.csAsserts that the slices do not depend on each other in a cycle (Orders → Billing → Orders). A slice may use another one. Each group of slices that depend on each other is reported once, with one of the shortest cycles and the dependencies that make it.
public void DoesNotHaveCycles(IEnumerable<IGrouping<string, TypeElement>> slices, string? message = null, string? slicesExpression = null)Parameters
slicesIEnumerable<IGrouping<string, TypeElement>>- The slices, such as the result of
TypeElementExtensions.SliceByNamespaceor ofGroupBy. A type must not be in several slices. messagestring?- The message that describes the failure.
slicesExpressionstring?- The expression of
slices.
Exceptions
AssertionException- The slices depend on each other in a cycle, or
slicesis empty. ArgumentException- Two slices have the same name, or a type is in several slices.
Example
var architecture = ArchitectureModel.FromAssemblyContaining<Order>();
var modules = architecture.Types.SliceByNamespace("SampleApp.Modules.{slice}");
var exception = Assert.Throws<AssertionException>(() => Assert.Architecture.DoesNotHaveCycles(modules));
Assert.StartsWith("""
Assert.Architecture.DoesNotHaveCycles() assertion failed: 1 cycle between slices.
Slices expression: modules
- Billing -> Shipping -> Billing
SampleApp.Modules.Billing.Invoice.Shipment has a property of type SampleApp.Modules.Shipping.Shipment
""".ReplaceLineEndings("\n"), exception.Message);