Could anyone say why am I getting these errors, given the configurations below?
Message:
ArchUnitNET.xUnit.FailedArchRuleException : "Classes that are Classes that are Classes that implement 'IRequest' and are not abstract and have name matching ".+Command$" and have name matching ".+Command$" should reside in namespace with full name matching ".+\.Commands\."" failed:
Core.Application.MasterDataSync.Commands.SynchronizeMasterDataCommand does reside in Core.Application.MasterDataSync.Commands
Core.Application.ManagerChain.Commands.CalculateManagerChainCommand does reside in Core.Application.ManagerChain.Commands
Core.Application.EmployeeSync.Commands.SynchronizeEmployeeCommand does reside in Core.Application.EmployeeSync.Commands
Core.Application.EmployeeFixedPaymentSummaries.Commands.SynchronizeLatestYearlyPaymentsCommand does reside in Core.Application.EmployeeFixedPaymentSummaries.Commands
Getting the assemblies:
using System.Reflection;
using ArchUnitNET.Domain;
using ArchUnitNET.Loader;
using Assembly = System.Reflection.Assembly;
namespace Corsica.Tests.ArchUnit;
public static class Corsica
{
public static readonly Architecture ARCHITECTURE =
new ArchLoader()
.LoadAssemblies(GetSolutionAssemblies())
.Build();
private static Assembly[] GetSolutionAssemblies()
{
var assemblies = Directory
.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
.Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x)))
.Where(x => x.FullName!.StartsWith("Core"));
return assemblies.ToArray();
}
}
The classes:
using MediatR;
namespace Core.Application.EmployeeFixedPaymentSummaries.Commands;
public class SynchronizeLatestYearlyPaymentsCommand : IRequest { }
using MediatR;
namespace Core.Application.EmployeeSync.Commands;
public class SynchronizeEmployeeCommand : IRequest { }
using MediatR;
namespace Core.Application.MasterDataSync.Commands;
public class SynchronizeMasterDataCommand : IRequest
{
}
using MediatR;
namespace Core.Application.ManagerChain.Commands;
public class CalculateManagerChainCommand : IRequest { }
The test class, which defines the rules that should supposedly pass.
using ArchUnitNET.Domain;
using ArchUnitNET.xUnit;
using MediatR;
using static ArchUnitNET.Fluent.ArchRuleDefinition;
namespace Corsica.Tests.ArchUnit;
public class Cqrs
{
private static readonly IObjectProvider<IType> NON_ABSTRACT_CLASSES_IMPLEMENTING_IREQUEST =
Classes()
.That().AreAssignableTo(typeof(IRequest<>)).Or().AreAssignableTo(typeof(IRequest)).As("Classes that implement 'IRequest'")
.And().AreNotAbstract()
.And().HaveName(".+Command$", true);
private static readonly IObjectProvider<IType> COMMANDS =
Classes().That().Are(NON_ABSTRACT_CLASSES_IMPLEMENTING_IREQUEST)
.And().HaveName(".+Command$", true);
private static readonly IObjectProvider<IType> QUERIES =
Classes().That().Are(NON_ABSTRACT_CLASSES_IMPLEMENTING_IREQUEST)
.And().HaveName(".+Query$", true);
[Fact]
public void ClassesInheritingFromIRequestShouldHaveNameEndingWithCommandOrQuery()
{
Classes().That().Are(NON_ABSTRACT_CLASSES_IMPLEMENTING_IREQUEST)
.Should().HaveName(".+(Command|Query)$", true).As("should have names ending with 'Command' or 'Query'")
.Check(Corsica.ARCHITECTURE);
}
[Fact]
public void CommandsShouldResideInCommandsNamespace()
{
Classes().That().Are(COMMANDS)
.Should().ResideInNamespace(".+\\.Commands\\.", true)
.Check(Corsica.ARCHITECTURE);
}
[Fact]
public void QueriesShouldResideInQueriesNamespace()
{
Classes().That().Are(QUERIES)
.Should().ResideInNamespace(".+\\.Queries\\.", true)
.Check(Corsica.ARCHITECTURE);
}
}
I wasn't expecting any errors. And it runs for the entire project, but only raises the error for those classes I mentioned.
Your example is working for me using
Classes().That().Are(COMMANDS).Should().ResideInNamespace(".+\\.Commands(\\.|$)", true).Check(Architecture);
This is, allow "Commands" to be at the end or inside the namespace.
(This would have been a comment on your post if I had the rep :) )