Posted on March 19, 2023
Read the onion architecture article located here since the remainder of this article will focus on writing a few architecture unit tests to ensure that the onion architecture is adhered to software architecture rules are best practices that tell how software should be designed and organized. These rules cover many aspects i.e. overall system structure, segregation of responsibilities, and integration between different application components. All stakeholders are not necessarily required to memorize all the software architecture rules. However, it is important for all members of the development team to have a general understanding of the rules and their importance in ensuring the quality and reliability of the system. In addition, even if code reviews are conducted, there is still a possibility that some unintentional violations of the software architecture rules may not be caught. This is where the use of unit tests can be beneficial. By writing unit tests that specifically target the software architecture rules, developers can ensure that the system adheres to those rules and catch any violations early on in the development process. If a stakeholder who was responsible for enforcing software architecture rules leaves the company, it is important to ensure that their knowledge and responsibilities are transferred to someone else on the team and additionally can help identify violations of the software architecture rules and alert the development team to potential issues. Read the onion architecture article located here, we will focus on writing unit tests to enforce rules in the project. The example below uses ArchUnitNET and xUnit. Rule 01: The domain layer should not have a reference to any other layer within the application core. Rule 02: The domain layer should not have references to the repositories layer. Rule 03: The domain layer should not have references to the Presentation layer. Rule 04: The domain layer should not have references to the persistence layer. Rule 05: The Presentation Layer should have a reference to the domain layer Note: New unit test added to existing project solution here Please download from Github. See the screenshot for reference.What do you mean by software architecture rules?
Who are stack holders responsible for Enforcing software architecture rules?
Why software architecture rules?
Getting Started
PS> Install-Package ArchUnitNET.xUnit
PS> Install-Package ArchUnitNET.NUnit
PS> Install-Package ArchUnitNET.MSTestV2
Adding Rules/Guideline
Test Run - Passed
Sample Unit Test
using ArchUnitNET.Domain;
using ArchUnitNET.Loader;
using ArchUnitNET.Fluent;
using static ArchUnitNET.Fluent.ArchRuleDefinition;
using ArchUnitNET.Domain.Extensions;
using ArchUnitNET.MSTestV2;
using Autofac;
using OnionDemo.Persistance;
using OnionDemo.Services;
namespace OnionDemo.Core.Policies.Tests
{
public class ArchitectureViolationsRuleTest
{
private static readonly Architecture Architecture = new ArchLoader().LoadAssemblies(
System.Reflection.Assembly.Load("OnionDemo.Domain"),
System.Reflection.Assembly.Load("OnionDemo.Services"),
System.Reflection.Assembly.Load("OnionDemo.Persistance"),
System.Reflection.Assembly.Load("OnionDemo.Presentation")).Build();
private readonly IObjectProvider<IType> DomainModelLayer = Types().That().ResideInAssembly("OnionDemo.Domain");
private readonly IObjectProvider<IType> DomainServiceLayer = Types().That().ResideInNamespace("OnionDemo.Services");
private readonly IObjectProvider<IType> PersistanceLayer = Types().That().ResideInNamespace("OnionDemo.Persistance");
private readonly IObjectProvider<IType> PresentationLayer = Types().That().ResideInNamespace("OnionDemo.Presentation");
[Fact]
public void TestLayerShouldContainsPrerequisiteAbstractions()
{
var domainModelInterfaces = Architecture.Interfaces.Where(x =>
x.NameEndsWith("Repository") ||
x.NameEndsWith("Manager"));
Assert.True(domainModelInterfaces.Any());
}
[Fact]
public void TestLayerForViolations()
{
// Create a new container builder
var builder = new ContainerBuilder();
// Register the module to be tested
builder.RegisterModule(new ServiceAutofacModule());
builder.RegisterModule(new PersistanceAutofacModule());
builder.Build();
//The domain layer should not have reference to any other layer within the application core.
IArchRule layerdRule = Types().That().Are(DomainModelLayer)
.Should().NotDependOnAny(DomainServiceLayer)
.Because("The domain model layer should not have reference to any other layer within the application core.");
layerdRule.Check(Architecture);
//Domain layer should not have references to the repositories layer.
layerdRule = Types().That().Are(DomainModelLayer)
.Should().NotDependOnAny(PersistanceLayer)
.Because("The Domain layer should not have references to the repositories layer.");
layerdRule.Check(Architecture);
//Domain layer should not have references to the Presentation layer.
layerdRule = Types().That().Are(DomainModelLayer)
.Should().NotDependOnAny(PresentationLayer)
.Because("The Domain layer should not have references to the Presentation layer.");
layerdRule.Check(Architecture);
//Domain layer should not have references to the Persistance layer.
layerdRule = Types().That().Are(DomainServiceLayer)
.Should().NotDependOnAny(PersistanceLayer)
.Because("Domain layer should not have references to the Persistance layer.");
layerdRule.Check(Architecture);
//The Presentation Layer should have reference to domain layer
layerdRule = Types().That().Are(PresentationLayer)
.Should().DependOnAny(DomainModelLayer);
layerdRule.Check(Architecture);
}
}
}
Summary