From acde9ec22a292d0214d7eaaf82bbd2215d97e055 Mon Sep 17 00:00:00 2001 From: Svrnty Date: Sat, 28 Feb 2026 17:36:34 -0500 Subject: [PATCH] test: add FluentValidation tests for command and query validators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests verifying that FluentValidation integrates correctly with the CQRS discovery and handler registration pipeline. 🤖 Generated with [Claude Code](https://claude.ai/claude-code) Co-Authored-By: Svrnty Inc. --- .../FluentValidationTests.cs | 184 ++++++++++++++++++ .../Svrnty.CQRS.Tests.csproj | 4 + 2 files changed, 188 insertions(+) create mode 100644 tests/Svrnty.CQRS.Tests/FluentValidationTests.cs diff --git a/tests/Svrnty.CQRS.Tests/FluentValidationTests.cs b/tests/Svrnty.CQRS.Tests/FluentValidationTests.cs new file mode 100644 index 0000000..38afe40 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/FluentValidationTests.cs @@ -0,0 +1,184 @@ +using FluentValidation; +using Microsoft.Extensions.DependencyInjection; +using Svrnty.CQRS.Abstractions; +using Svrnty.CQRS.Abstractions.Discovery; + +namespace Svrnty.CQRS.Tests; + +// Validator for CreatePersonCommand +public class CreatePersonCommandValidator : AbstractValidator +{ + public CreatePersonCommandValidator() + { + RuleFor(x => x.FirstName).NotEmpty().WithMessage("FirstName is required"); + RuleFor(x => x.LastName).NotEmpty().WithMessage("LastName is required"); + } +} + +// Validator for PersonQuery +public class PersonQueryValidator : AbstractValidator +{ + public PersonQueryValidator() + { + RuleFor(x => x.NameFilter).MaximumLength(100).WithMessage("NameFilter too long"); + } +} + +public class FluentValidationTests +{ + [Fact] + public void AddCommand_WithValidator_RegistersHandlerAndValidator() + { + var services = new ServiceCollection(); + Svrnty.CQRS.FluentValidation.ServiceCollectionExtensions + .AddCommand(services); + + var provider = services.BuildServiceProvider(); + + var handler = provider.GetService>(); + var validator = provider.GetService>(); + + Assert.NotNull(handler); + Assert.NotNull(validator); + Assert.IsType(handler); + Assert.IsType(validator); + } + + [Fact] + public void AddCommand_WithResultAndValidator_RegistersHandlerAndValidator() + { + var services = new ServiceCollection(); + Svrnty.CQRS.FluentValidation.ServiceCollectionExtensions + .AddCommand(services); + + var provider = services.BuildServiceProvider(); + + var handler = provider.GetService>(); + var validator = provider.GetService>(); + + Assert.NotNull(handler); + Assert.NotNull(validator); + } + + [Fact] + public void AddCommand_WithResultAndValidator_RegistersCommandMeta() + { + var services = new ServiceCollection(); + Svrnty.CQRS.FluentValidation.ServiceCollectionExtensions + .AddCommand(services); + + var provider = services.BuildServiceProvider(); + var metas = provider.GetServices().ToList(); + + Assert.Single(metas); + Assert.Equal(typeof(CreatePersonCommand), metas[0].CommandType); + Assert.Equal(typeof(CreatePersonResult), metas[0].CommandResultType); + } + + [Fact] + public void AddQuery_WithValidator_RegistersHandlerAndValidator() + { + var services = new ServiceCollection(); + Svrnty.CQRS.FluentValidation.ServiceCollectionExtensions + .AddQuery, PersonQueryHandler, PersonQueryValidator>(services); + + var provider = services.BuildServiceProvider(); + + var handler = provider.GetService>>(); + var validator = provider.GetService>(); + + Assert.NotNull(handler); + Assert.NotNull(validator); + Assert.IsType(handler); + Assert.IsType(validator); + } + + [Fact] + public async Task Validator_RejectsInvalidCommand() + { + var validator = new CreatePersonCommandValidator(); + var command = new CreatePersonCommand { FirstName = "", LastName = "" }; + + var result = await validator.ValidateAsync(command); + + Assert.False(result.IsValid); + Assert.Equal(2, result.Errors.Count); + } + + [Fact] + public async Task Validator_AcceptsValidCommand() + { + var validator = new CreatePersonCommandValidator(); + var command = new CreatePersonCommand { FirstName = "John", LastName = "Doe" }; + + var result = await validator.ValidateAsync(command); + + Assert.True(result.IsValid); + Assert.Empty(result.Errors); + } + + [Fact] + public async Task Validator_ResolvedFromDI_WorksCorrectly() + { + var services = new ServiceCollection(); + Svrnty.CQRS.FluentValidation.ServiceCollectionExtensions + .AddCommand(services); + + var provider = services.BuildServiceProvider(); + var validator = provider.GetRequiredService>(); + + var invalidResult = await validator.ValidateAsync(new CreatePersonCommand { FirstName = "", LastName = "" }); + Assert.False(invalidResult.IsValid); + + var validResult = await validator.ValidateAsync(new CreatePersonCommand { FirstName = "Jane", LastName = "Doe" }); + Assert.True(validResult.IsValid); + } + + [Fact] + public void CqrsBuilder_AddCommand_WithValidator_RegistersBoth() + { + var services = new ServiceCollection(); + services.AddSvrntyCqrs(builder => + { + Svrnty.CQRS.FluentValidation.CqrsBuilderExtensions + .AddCommand(builder); + }); + + var provider = services.BuildServiceProvider(); + + Assert.NotNull(provider.GetService>()); + Assert.NotNull(provider.GetService>()); + } + + [Fact] + public void CqrsBuilder_AddCommand_WithResultAndValidator_RegistersBoth() + { + var services = new ServiceCollection(); + services.AddSvrntyCqrs(builder => + { + Svrnty.CQRS.FluentValidation.CqrsBuilderExtensions + .AddCommand(builder); + }); + + var provider = services.BuildServiceProvider(); + + Assert.NotNull(provider.GetService>()); + Assert.NotNull(provider.GetService>()); + } + + [Fact] + public void CqrsBuilder_AddQuery_WithValidator_RegistersBoth() + { + var services = new ServiceCollection(); + services.AddSvrntyCqrs(builder => + { + Svrnty.CQRS.FluentValidation.CqrsBuilderExtensions + .AddQuery, PersonQueryHandler, PersonQueryValidator>(builder); + }); + + var provider = services.BuildServiceProvider(); + + Assert.NotNull(provider.GetService>>()); + Assert.NotNull(provider.GetService>()); + } +} diff --git a/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj b/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj index d6b29b3..0599c8f 100644 --- a/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj +++ b/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj @@ -16,11 +16,15 @@ all + + + +