ArchUnitNET

User Guide

1. Installation

To use ArchUnitNET, install the ArchUnitNET package from NuGet:

PS> Install-Package ArchUnitNET

If you want to use xUnit or NUnit for your unit tests, you should instead install the corresponding ArchUnit extension:

PS> Install-Package ArchUnitNET.xUnit
PS> Install-Package ArchUnitNET.NUnit

2. Quick Start

Create a test class to start testing. We used xUnit with the ArchUnit extension here, but it works similarly with NUnit or other Unit Test Frameworks.

Find this example code here.

2.1. Directives


using ArchUnitNET.Domain;
using ArchUnitNET.Loader;
using ArchUnitNET.Fluent;
using Xunit;

//add a using directive to ArchUnitNET.Fluent.ArchRuleDefinition to easily define ArchRules
using static ArchUnitNET.Fluent.ArchRuleDefinition;

2.2. Load Architecture

Load your architecture once at the start to maximize performance of your tests replace <ExampleClass> and <ForbiddenClass> with classes from the assemblies you want to test

private static readonly Architecture Architecture =
    new ArchLoader().LoadAssemblies(typeof(ExampleClass).Assembly, 
    typeof(ForbiddenClass).Assembly).Build();

2.3. Declare Layers

Declare variables you'll use throughout your tests up here

//use As() to give your variables a custom description
private readonly IObjectProvider<IType> ExampleLayer =
    Types().That().ResideInAssembly("ExampleAssembly").As("Example Layer");

private readonly IObjectProvider<Class> ExampleClasses =
    Classes().That().ImplementInterface("IExampleInterface").As("Example Classes");

private readonly IObjectProvider<IType> ForbiddenLayer =
    Types().That().ResideInNamespace("ForbiddenNamespace").As("Forbidden Layer");

private readonly IObjectProvider<Interface> ForbiddenInterfaces =
    Interfaces().That().HaveFullNameContaining("forbidden").As("Forbidden Interfaces");

2.4. Test Cases

Testing if above defined "ExampleClasses" reside in "ExampleLayer"

[Fact]
public void TypesShouldBeInCorrectLayer()
{
    IArchRule exampleClassesShouldBeInExampleLayer =
        Classes().That().Are(ExampleClasses).Should().Be(ExampleLayer);
    IArchRule forbiddenInterfacesShouldBeInForbiddenLayer =
        Interfaces().That().Are(ForbiddenInterfaces).Should().Be(ForbiddenLayer);

    //check if your architecture fulfills your rules
    exampleClassesShouldBeInExampleLayer.Check(Architecture);
    forbiddenInterfacesShouldBeInForbiddenLayer.Check(Architecture);

    //you can also combine your rules
    IArchRule combinedArchRule =
        exampleClassesShouldBeInExampleLayer
        .And(forbiddenInterfacesShouldBeInForbiddenLayer);

    combinedArchRule.Check(Architecture);
}

Testing if the types in "ExampleLayer" depend on any object in "ForbiddenLayer"

[Fact]
public void ExampleLayerShouldNotAccessForbiddenLayer()
{
    //you can give your rules a custom reason, which is displayed when it fails
    //(together with the types that failed the rule)
    IArchRule exampleLayerShouldNotAccessForbiddenLayer = Types().That()
        .Are(ExampleLayer).Should().NotDependOnAny(ForbiddenLayer)
        .Because("it's forbidden");
    exampleLayerShouldNotAccessForbiddenLayer.Check(Architecture);
}

Testing naming of classes implementing "ForbiddenInterfaces"

[Fact]
public void ForbiddenClassesShouldHaveCorrectName()
{
    Classes().That().AreAssignableTo(ForbiddenInterfaces)
        .Should().HaveNameContaining("forbidden").Check(Architecture);
}

Testing if "ExampleClasses" call any method declared in "ForbiddenLayer" or with name containing "forbidden"

[Fact]
public void ExampleClassesShouldNotCallForbiddenMethods()
{
    Classes().That().Are(ExampleClasses).Should()
        .NotCallAny(MethodMembers().That()
        .AreDeclaredIn(ForbiddenLayer).Or().HaveNameContaining("forbidden"))
        .Check(Architecture);
}

3. What to Check

The following section illustrates some typical checks you could do with ArchUnitNET.

Find this example code here.

3.1. Namespace Dependency Rule

Namespace_Dependency

IArchRule rule = Types().That().ResideInNamespace("Model").Should()
                    .NotDependOnAny(Types().That().ResideInNamespace("Controller"));

3.2. Class Dependency Rule

Class_Dependency

IArchRule rule = Classes().That().AreAssignableTo(typeof(ICar)).Should()
                    .NotDependOnAny(Classes().That().AreAssignableTo(typeof(ICanvas)));

3.3. Inheritance Naming Rule

Inheritance_Naming

IArchRule rule = Classes().That().AreAssignableTo(typeof(ICar)).Should()
                    .HaveNameContaining("Car");

3.4. Class Namespace Containment Rule

Class_Namespace_Containment

IArchRule rule = Classes().That().HaveNameContaining("Canvas").Should()
                     .ResideInNamespace(typeof(ICanvas).Namespace);

3.5. Attribute Access Rule

Attribute_Access

IArchRule rule = Classes().That().DoNotHaveAnyAttributes(typeof(Display)).Should()
                    .NotDependOnAny(Classes().That().AreAssignableTo(typeof(ICanvas)));

3.6. Cycle Rule

Cycle

IArchRule rule = Slices().Matching("Module.(*)").Should()
                    .BeFreeOfCycles();

4. How to check

To get a meaningful error message we recommend using the xUnit or NUnit extension.

4.1 ArchUnitNET xUnit/NUnit extension

IArchRule someRule = ...;
someRule.check(Architecture);

4.2 ArchUnitNET no extension

IArchRule someRule = ...;
bool checkedRule = someRule.HasNoViolations(Architecture);
Assert.True(checkedRule);

5. Further Reading and Examples

A complete overview of all available methods can be found here.

Check out example code on Github.