skills/quality/architectural-fitness/SKILL.md
Use when adding NetArchTest architecture tests to enforce dependency rules.
npx skillsauth add faysilalshareef/dotnet-ai-kit architectural-fitnessInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
NetArchTest validates assembly dependencies and naming conventionsHandler, etc.<!-- Test project .csproj -->
<PackageReference Include="NetArchTest.Rules" />
<PackageReference Include="FluentAssertions" />
namespace {Company}.{Domain}.Tests.Architecture;
public sealed class LayerDependencyTests
{
private static readonly Assembly DomainAssembly =
typeof(Order).Assembly;
private static readonly Assembly ApplicationAssembly =
typeof(CreateOrderCommand).Assembly;
private static readonly Assembly InfrastructureAssembly =
typeof(ApplicationDbContext).Assembly;
[Fact]
public void Domain_ShouldNotDependOn_Application()
{
var result = Types.InAssembly(DomainAssembly)
.ShouldNot()
.HaveDependencyOn(ApplicationAssembly.GetName().Name!)
.GetResult();
result.IsSuccessful.Should().BeTrue(
because: FormatFailures(result));
}
[Fact]
public void Domain_ShouldNotDependOn_Infrastructure()
{
var result = Types.InAssembly(DomainAssembly)
.ShouldNot()
.HaveDependencyOn(InfrastructureAssembly.GetName().Name!)
.GetResult();
result.IsSuccessful.Should().BeTrue(
because: FormatFailures(result));
}
[Fact]
public void Application_ShouldNotDependOn_Infrastructure()
{
var result = Types.InAssembly(ApplicationAssembly)
.ShouldNot()
.HaveDependencyOn(InfrastructureAssembly.GetName().Name!)
.GetResult();
result.IsSuccessful.Should().BeTrue(
because: FormatFailures(result));
}
private static string FormatFailures(TestResult result) =>
string.Join(", ", result.FailingTypeNames ?? []);
}
namespace {Company}.{Domain}.Tests.Architecture;
public sealed class NamingConventionTests
{
[Fact]
public void Handlers_ShouldEndWith_Handler()
{
var result = Types.InAssembly(typeof(CreateOrderHandler).Assembly)
.That()
.ImplementInterface(typeof(IRequestHandler<,>))
.Should()
.HaveNameEndingWith("Handler")
.GetResult();
result.IsSuccessful.Should().BeTrue(
because: FormatFailures(result));
}
[Fact]
public void Validators_ShouldEndWith_Validator()
{
var result = Types.InAssembly(typeof(CreateOrderValidator).Assembly)
.That()
.Inherit(typeof(AbstractValidator<>))
.Should()
.HaveNameEndingWith("Validator")
.GetResult();
result.IsSuccessful.Should().BeTrue(
because: FormatFailures(result));
}
[Fact]
public void Entities_ShouldHave_PrivateSetters()
{
var entityTypes = Types.InAssembly(typeof(Order).Assembly)
.That()
.ResideInNamespace("{Company}.{Domain}.Query.Domain")
.GetTypes();
foreach (var type in entityTypes)
{
var publicSetters = type.GetProperties()
.Where(p => p.SetMethod?.IsPublic == true
&& p.Name != "ETag"); // Cosmos exception
publicSetters.Should().BeEmpty(
because: $"{type.Name} should use private setters");
}
}
}
[Fact]
public void CommandHandlers_ShouldNotDirectly_AccessDbContext()
{
var result = Types.InAssembly(typeof(CreateOrderHandler).Assembly)
.That()
.HaveNameEndingWith("Handler")
.ShouldNot()
.HaveDependencyOn("Microsoft.EntityFrameworkCore")
.GetResult();
result.IsSuccessful.Should().BeTrue(
because: "Handlers should use ICommitEventService, not DbContext directly");
}
[Fact]
public void EventData_ShouldBe_Sealed_Records()
{
var eventDataTypes = Types.InAssembly(typeof(OrderCreatedData).Assembly)
.That()
.ImplementInterface(typeof(IEventData))
.GetTypes();
foreach (var type in eventDataTypes)
{
type.IsSealed.Should().BeTrue(
because: $"{type.Name} should be sealed");
type.IsClass.Should().BeTrue(); // records are classes
}
}
| Anti-Pattern | Correct Approach | |---|---| | No architecture tests | Add tests for critical dependency rules | | Tests only at creation | Run in CI to prevent drift | | Overly strict rules | Focus on critical boundaries | | Ignoring test failures | Fix violations or update rules with justification |
# Find NetArchTest
grep -r "NetArchTest" --include="*.csproj" tests/
# Find architecture tests
grep -r "Types.InAssembly\|ShouldNot.*HaveDependencyOn" --include="*.cs" tests/
# Find naming convention tests
grep -r "HaveNameEndingWith" --include="*.cs" tests/
data-ai
Use when about to claim work is complete, fixed, passing, or ready — before committing, creating PRs, or moving to the next task. Requires running verification commands and confirming output before making any success claims.
development
Use when encountering any bug, test failure, build error, or unexpected behavior — before proposing fixes or making changes.
development
Use when checkpointing, wrapping up, or handing off an AI-assisted development session.
development
Use when following the Specification-Driven Development lifecycle from plan through ship.