From 92231df7450622646362ee20b223494ccee14810 Mon Sep 17 00:00:00 2001 From: Svrnty Date: Fri, 27 Feb 2026 18:38:44 -0500 Subject: [PATCH] test: add xUnit test project for Svrnty.CQRS core library Add tests/Svrnty.CQRS.Tests with 61 tests covering: - CommandMeta and QueryMeta metadata creation and naming conventions - CommandDiscovery and QueryDiscovery lookup, existence, and enumeration - DI service registration for commands (with/without result) and queries - Full pipeline integration (register -> discover -> resolve) - CqrsBuilder fluent API configuration - CqrsConfiguration generic storage and mapping callbacks - Handler execution via DI-resolved instances Co-Authored-By: Svrnty Inc. --- Svrnty.CQRS.sln | 19 ++ .../CommandDiscoveryTests.cs | 124 ++++++++++++ tests/Svrnty.CQRS.Tests/CommandMetaTests.cs | 64 +++++++ .../CqrsConfigurationTests.cs | 106 +++++++++++ tests/Svrnty.CQRS.Tests/Fakes.cs | 81 ++++++++ tests/Svrnty.CQRS.Tests/GlobalUsings.cs | 1 + tests/Svrnty.CQRS.Tests/HandlerTests.cs | 64 +++++++ .../Svrnty.CQRS.Tests/QueryDiscoveryTests.cs | 124 ++++++++++++ tests/Svrnty.CQRS.Tests/QueryMetaTests.cs | 57 ++++++ .../ServiceRegistrationTests.cs | 180 ++++++++++++++++++ .../Svrnty.CQRS.Tests.csproj | 26 +++ 11 files changed, 846 insertions(+) create mode 100644 tests/Svrnty.CQRS.Tests/CommandDiscoveryTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/CommandMetaTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/CqrsConfigurationTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/Fakes.cs create mode 100644 tests/Svrnty.CQRS.Tests/GlobalUsings.cs create mode 100644 tests/Svrnty.CQRS.Tests/HandlerTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/QueryDiscoveryTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/QueryMetaTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/ServiceRegistrationTests.cs create mode 100644 tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj diff --git a/Svrnty.CQRS.sln b/Svrnty.CQRS.sln index 37176b1..6947cc7 100644 --- a/Svrnty.CQRS.sln +++ b/Svrnty.CQRS.sln @@ -43,6 +43,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svrnty.CQRS.Events.Abstract EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svrnty.CQRS.Events.RabbitMQ", "Svrnty.CQRS.Events.RabbitMQ\Svrnty.CQRS.Events.RabbitMQ.csproj", "{3C7412EF-13C2-41F3-9D4C-D2BEC4843C8C}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svrnty.CQRS.Tests", "tests\Svrnty.CQRS.Tests\Svrnty.CQRS.Tests.csproj", "{BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -257,10 +261,25 @@ Global {3C7412EF-13C2-41F3-9D4C-D2BEC4843C8C}.Release|x64.Build.0 = Release|Any CPU {3C7412EF-13C2-41F3-9D4C-D2BEC4843C8C}.Release|x86.ActiveCfg = Release|Any CPU {3C7412EF-13C2-41F3-9D4C-D2BEC4843C8C}.Release|x86.Build.0 = Release|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Debug|x64.ActiveCfg = Debug|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Debug|x64.Build.0 = Debug|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Debug|x86.ActiveCfg = Debug|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Debug|x86.Build.0 = Debug|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Release|Any CPU.Build.0 = Release|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Release|x64.ActiveCfg = Release|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Release|x64.Build.0 = Release|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Release|x86.ActiveCfg = Release|Any CPU + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BCB3DD95-DFDB-452C-A0AD-AA657AE0C049} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D6D431EA-C04F-462B-8033-60F510FEB49E} EndGlobalSection diff --git a/tests/Svrnty.CQRS.Tests/CommandDiscoveryTests.cs b/tests/Svrnty.CQRS.Tests/CommandDiscoveryTests.cs new file mode 100644 index 0000000..76898f6 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/CommandDiscoveryTests.cs @@ -0,0 +1,124 @@ +using Svrnty.CQRS.Abstractions.Discovery; +using Svrnty.CQRS.Discovery; + +namespace Svrnty.CQRS.Tests; + +public class CommandDiscoveryTests +{ + private static CommandDiscovery CreateDiscovery(params ICommandMeta[] metas) + { + return new CommandDiscovery(metas); + } + + [Fact] + public void GetCommands_ReturnsAllRegistered() + { + var meta1 = new CommandMeta(typeof(CreatePersonCommand), typeof(object), typeof(CreatePersonResult)); + var meta2 = new CommandMeta(typeof(DeletePersonCommand), typeof(object)); + var discovery = CreateDiscovery(meta1, meta2); + + var commands = discovery.GetCommands().ToList(); + + Assert.Equal(2, commands.Count); + } + + [Fact] + public void GetCommands_ReturnsEmpty_WhenNoneRegistered() + { + var discovery = CreateDiscovery(); + + var commands = discovery.GetCommands().ToList(); + + Assert.Empty(commands); + } + + [Fact] + public void FindCommand_ByName_ReturnsCorrectMeta() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object), typeof(CreatePersonResult)); + var discovery = CreateDiscovery(meta); + + var found = discovery.FindCommand("CreatePerson"); + + Assert.NotNull(found); + Assert.Equal(typeof(CreatePersonCommand), found.CommandType); + } + + [Fact] + public void FindCommand_ByName_ReturnsNull_WhenNotFound() + { + var discovery = CreateDiscovery(); + + var found = discovery.FindCommand("NonExistent"); + + Assert.Null(found); + } + + [Fact] + public void FindCommand_ByType_ReturnsCorrectMeta() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object), typeof(CreatePersonResult)); + var discovery = CreateDiscovery(meta); + + var found = discovery.FindCommand(typeof(CreatePersonCommand)); + + Assert.NotNull(found); + Assert.Equal("CreatePerson", found.Name); + } + + [Fact] + public void FindCommand_ByType_ReturnsNull_WhenNotFound() + { + var discovery = CreateDiscovery(); + + var found = discovery.FindCommand(typeof(CreatePersonCommand)); + + Assert.Null(found); + } + + [Fact] + public void CommandExists_ByName_ReturnsTrue_WhenFound() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object)); + var discovery = CreateDiscovery(meta); + + Assert.True(discovery.CommandExists("CreatePerson")); + } + + [Fact] + public void CommandExists_ByName_ReturnsFalse_WhenNotFound() + { + var discovery = CreateDiscovery(); + + Assert.False(discovery.CommandExists("CreatePerson")); + } + + [Fact] + public void CommandExists_ByType_ReturnsTrue_WhenFound() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object)); + var discovery = CreateDiscovery(meta); + + Assert.True(discovery.CommandExists(typeof(CreatePersonCommand))); + } + + [Fact] + public void CommandExists_ByType_ReturnsFalse_WhenNotFound() + { + var discovery = CreateDiscovery(); + + Assert.False(discovery.CommandExists(typeof(CreatePersonCommand))); + } + + [Fact] + public void FindCommand_WithCustomName_FindsByAttributeName() + { + var meta = new CommandMeta(typeof(CreateWidgetCommand), typeof(object)); + var discovery = CreateDiscovery(meta); + + var found = discovery.FindCommand("customCreate"); + + Assert.NotNull(found); + Assert.Equal(typeof(CreateWidgetCommand), found.CommandType); + } +} diff --git a/tests/Svrnty.CQRS.Tests/CommandMetaTests.cs b/tests/Svrnty.CQRS.Tests/CommandMetaTests.cs new file mode 100644 index 0000000..d150f66 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/CommandMetaTests.cs @@ -0,0 +1,64 @@ +using Svrnty.CQRS.Abstractions.Discovery; + +namespace Svrnty.CQRS.Tests; + +public class CommandMetaTests +{ + [Fact] + public void Name_StripsCommandSuffix() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object)); + Assert.Equal("CreatePerson", meta.Name); + } + + [Fact] + public void Name_UsesCommandNameAttribute_WhenPresent() + { + var meta = new CommandMeta(typeof(CreateWidgetCommand), typeof(object)); + Assert.Equal("customCreate", meta.Name); + } + + [Fact] + public void LowerCamelCaseName_ConvertsFirstCharToLower() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object)); + Assert.Equal("createPerson", meta.LowerCamelCaseName); + } + + [Fact] + public void LowerCamelCaseName_PreservesAlreadyLowerCase() + { + var meta = new CommandMeta(typeof(CreateWidgetCommand), typeof(object)); + // customCreate -> already lower first char + Assert.Equal("customCreate", meta.LowerCamelCaseName); + } + + [Fact] + public void CommandType_IsSetCorrectly() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object)); + Assert.Equal(typeof(CreatePersonCommand), meta.CommandType); + } + + [Fact] + public void ServiceType_IsSetCorrectly() + { + var serviceType = typeof(object); + var meta = new CommandMeta(typeof(CreatePersonCommand), serviceType); + Assert.Equal(serviceType, meta.ServiceType); + } + + [Fact] + public void CommandResultType_IsSetCorrectly_WithThreeArgConstructor() + { + var meta = new CommandMeta(typeof(CreatePersonCommand), typeof(object), typeof(CreatePersonResult)); + Assert.Equal(typeof(CreatePersonResult), meta.CommandResultType); + } + + [Fact] + public void CommandResultType_IsNull_WithTwoArgConstructor() + { + var meta = new CommandMeta(typeof(DeletePersonCommand), typeof(object)); + Assert.Null(meta.CommandResultType); + } +} diff --git a/tests/Svrnty.CQRS.Tests/CqrsConfigurationTests.cs b/tests/Svrnty.CQRS.Tests/CqrsConfigurationTests.cs new file mode 100644 index 0000000..f0a24cf --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/CqrsConfigurationTests.cs @@ -0,0 +1,106 @@ +using Svrnty.CQRS.Configuration; + +namespace Svrnty.CQRS.Tests; + +public class CqrsConfigurationTests +{ + private class TestConfig + { + public string Value { get; set; } = string.Empty; + } + + private class OtherConfig + { + public int Number { get; set; } + } + + [Fact] + public void SetConfiguration_CanBeRetrieved() + { + var config = new CqrsConfiguration(); + var testConfig = new TestConfig { Value = "hello" }; + + config.SetConfiguration(testConfig); + + var retrieved = config.GetConfiguration(); + Assert.NotNull(retrieved); + Assert.Equal("hello", retrieved.Value); + } + + [Fact] + public void GetConfiguration_ReturnsNull_WhenNotSet() + { + var config = new CqrsConfiguration(); + + var retrieved = config.GetConfiguration(); + + Assert.Null(retrieved); + } + + [Fact] + public void HasConfiguration_ReturnsTrue_WhenSet() + { + var config = new CqrsConfiguration(); + config.SetConfiguration(new TestConfig()); + + Assert.True(config.HasConfiguration()); + } + + [Fact] + public void HasConfiguration_ReturnsFalse_WhenNotSet() + { + var config = new CqrsConfiguration(); + + Assert.False(config.HasConfiguration()); + } + + [Fact] + public void SetConfiguration_OverwritesPrevious() + { + var config = new CqrsConfiguration(); + config.SetConfiguration(new TestConfig { Value = "first" }); + config.SetConfiguration(new TestConfig { Value = "second" }); + + var retrieved = config.GetConfiguration(); + Assert.Equal("second", retrieved!.Value); + } + + [Fact] + public void MultipleConfigTypes_AreIndependent() + { + var config = new CqrsConfiguration(); + config.SetConfiguration(new TestConfig { Value = "test" }); + config.SetConfiguration(new OtherConfig { Number = 42 }); + + Assert.Equal("test", config.GetConfiguration()!.Value); + Assert.Equal(42, config.GetConfiguration()!.Number); + } + + [Fact] + public void ExecuteMappingCallbacks_InvokesAllCallbacks() + { + var config = new CqrsConfiguration(); + var callCount = 0; + + config.AddMappingCallback(_ => callCount++); + config.AddMappingCallback(_ => callCount++); + + config.ExecuteMappingCallbacks(new object()); + + Assert.Equal(2, callCount); + } + + [Fact] + public void ExecuteMappingCallbacks_PassesAppObject() + { + var config = new CqrsConfiguration(); + object? receivedApp = null; + + config.AddMappingCallback(app => receivedApp = app); + + var expected = new object(); + config.ExecuteMappingCallbacks(expected); + + Assert.Same(expected, receivedApp); + } +} diff --git a/tests/Svrnty.CQRS.Tests/Fakes.cs b/tests/Svrnty.CQRS.Tests/Fakes.cs new file mode 100644 index 0000000..18f8c7e --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/Fakes.cs @@ -0,0 +1,81 @@ +using Svrnty.CQRS.Abstractions; +using Svrnty.CQRS.Abstractions.Attributes; + +namespace Svrnty.CQRS.Tests; + +// Commands +public class CreatePersonCommand +{ + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; +} + +public class DeletePersonCommand +{ + public int Id { get; set; } +} + +[CommandName("customCreate")] +public class CreateWidgetCommand +{ + public string Name { get; set; } = string.Empty; +} + +// Command results +public class CreatePersonResult +{ + public int Id { get; set; } +} + +// Queries +public class PersonQuery +{ + public string? NameFilter { get; set; } +} + +[QueryName("customPersonLookup")] +public class PersonLookupQuery +{ + public int Id { get; set; } +} + +// Handlers +public class CreatePersonCommandHandler : ICommandHandler +{ + public Task HandleAsync(CreatePersonCommand command, CancellationToken cancellationToken = default) + { + return Task.FromResult(new CreatePersonResult { Id = 1 }); + } +} + +public class DeletePersonCommandHandler : ICommandHandler +{ + public Task HandleAsync(DeletePersonCommand command, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } +} + +public class CreateWidgetCommandHandler : ICommandHandler +{ + public Task HandleAsync(CreateWidgetCommand command, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } +} + +public class PersonQueryHandler : IQueryHandler> +{ + public Task> HandleAsync(PersonQuery query, CancellationToken cancellationToken = default) + { + return Task.FromResult>(["Alice", "Bob"]); + } +} + +public class PersonLookupQueryHandler : IQueryHandler +{ + public Task HandleAsync(PersonLookupQuery query, CancellationToken cancellationToken = default) + { + return Task.FromResult("Alice"); + } +} diff --git a/tests/Svrnty.CQRS.Tests/GlobalUsings.cs b/tests/Svrnty.CQRS.Tests/GlobalUsings.cs new file mode 100644 index 0000000..c802f44 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; diff --git a/tests/Svrnty.CQRS.Tests/HandlerTests.cs b/tests/Svrnty.CQRS.Tests/HandlerTests.cs new file mode 100644 index 0000000..439e893 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/HandlerTests.cs @@ -0,0 +1,64 @@ +using Microsoft.Extensions.DependencyInjection; +using Svrnty.CQRS.Abstractions; + +namespace Svrnty.CQRS.Tests; + +public class HandlerTests +{ + [Fact] + public async Task CommandHandler_WithResult_ExecutesCorrectly() + { + var services = new ServiceCollection(); + services.AddCommand(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService>(); + + var result = await handler.HandleAsync(new CreatePersonCommand + { + FirstName = "John", + LastName = "Doe" + }); + + Assert.Equal(1, result.Id); + } + + [Fact] + public async Task CommandHandler_WithoutResult_ExecutesWithoutException() + { + var services = new ServiceCollection(); + services.AddCommand(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService>(); + + await handler.HandleAsync(new DeletePersonCommand { Id = 1 }); + } + + [Fact] + public async Task QueryHandler_ExecutesCorrectly() + { + var services = new ServiceCollection(); + services.AddQuery, PersonQueryHandler>(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService>>(); + + var result = await handler.HandleAsync(new PersonQuery()); + + Assert.Equal(["Alice", "Bob"], result); + } + + [Fact] + public async Task CommandHandler_SupportsCancellationToken() + { + var services = new ServiceCollection(); + services.AddCommand(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService>(); + + using var cts = new CancellationTokenSource(); + await handler.HandleAsync(new DeletePersonCommand { Id = 1 }, cts.Token); + } +} diff --git a/tests/Svrnty.CQRS.Tests/QueryDiscoveryTests.cs b/tests/Svrnty.CQRS.Tests/QueryDiscoveryTests.cs new file mode 100644 index 0000000..f05cfb2 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/QueryDiscoveryTests.cs @@ -0,0 +1,124 @@ +using Svrnty.CQRS.Abstractions.Discovery; +using Svrnty.CQRS.Discovery; + +namespace Svrnty.CQRS.Tests; + +public class QueryDiscoveryTests +{ + private static QueryDiscovery CreateDiscovery(params IQueryMeta[] metas) + { + return new QueryDiscovery(metas); + } + + [Fact] + public void GetQueries_ReturnsAllRegistered() + { + var meta1 = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + var meta2 = new QueryMeta(typeof(PersonLookupQuery), typeof(object), typeof(string)); + var discovery = CreateDiscovery(meta1, meta2); + + var queries = discovery.GetQueries().ToList(); + + Assert.Equal(2, queries.Count); + } + + [Fact] + public void GetQueries_ReturnsEmpty_WhenNoneRegistered() + { + var discovery = CreateDiscovery(); + + var queries = discovery.GetQueries().ToList(); + + Assert.Empty(queries); + } + + [Fact] + public void FindQuery_ByName_ReturnsCorrectMeta() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + var discovery = CreateDiscovery(meta); + + var found = discovery.FindQuery("Person"); + + Assert.NotNull(found); + Assert.Equal(typeof(PersonQuery), found.QueryType); + } + + [Fact] + public void FindQuery_ByName_ReturnsNull_WhenNotFound() + { + var discovery = CreateDiscovery(); + + var found = discovery.FindQuery("NonExistent"); + + Assert.Null(found); + } + + [Fact] + public void FindQuery_ByType_ReturnsCorrectMeta() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + var discovery = CreateDiscovery(meta); + + var found = discovery.FindQuery(typeof(PersonQuery)); + + Assert.NotNull(found); + Assert.Equal("Person", found.Name); + } + + [Fact] + public void FindQuery_ByType_ReturnsNull_WhenNotFound() + { + var discovery = CreateDiscovery(); + + var found = discovery.FindQuery(typeof(PersonQuery)); + + Assert.Null(found); + } + + [Fact] + public void QueryExists_ByName_ReturnsTrue_WhenFound() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + var discovery = CreateDiscovery(meta); + + Assert.True(discovery.QueryExists("Person")); + } + + [Fact] + public void QueryExists_ByName_ReturnsFalse_WhenNotFound() + { + var discovery = CreateDiscovery(); + + Assert.False(discovery.QueryExists("Person")); + } + + [Fact] + public void QueryExists_ByType_ReturnsTrue_WhenFound() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + var discovery = CreateDiscovery(meta); + + Assert.True(discovery.QueryExists(typeof(PersonQuery))); + } + + [Fact] + public void QueryExists_ByType_ReturnsFalse_WhenNotFound() + { + var discovery = CreateDiscovery(); + + Assert.False(discovery.QueryExists(typeof(PersonQuery))); + } + + [Fact] + public void FindQuery_WithCustomName_FindsByAttributeName() + { + var meta = new QueryMeta(typeof(PersonLookupQuery), typeof(object), typeof(string)); + var discovery = CreateDiscovery(meta); + + var found = discovery.FindQuery("customPersonLookup"); + + Assert.NotNull(found); + Assert.Equal(typeof(PersonLookupQuery), found.QueryType); + } +} diff --git a/tests/Svrnty.CQRS.Tests/QueryMetaTests.cs b/tests/Svrnty.CQRS.Tests/QueryMetaTests.cs new file mode 100644 index 0000000..00b622b --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/QueryMetaTests.cs @@ -0,0 +1,57 @@ +using Svrnty.CQRS.Abstractions.Discovery; + +namespace Svrnty.CQRS.Tests; + +public class QueryMetaTests +{ + [Fact] + public void Name_StripsQuerySuffix() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + Assert.Equal("Person", meta.Name); + } + + [Fact] + public void Name_UsesQueryNameAttribute_WhenPresent() + { + var meta = new QueryMeta(typeof(PersonLookupQuery), typeof(object), typeof(string)); + Assert.Equal("customPersonLookup", meta.Name); + } + + [Fact] + public void LowerCamelCaseName_ConvertsFirstCharToLower() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + Assert.Equal("person", meta.LowerCamelCaseName); + } + + [Fact] + public void Category_DefaultsToBasicQuery() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + Assert.Equal("BasicQuery", meta.Category); + } + + [Fact] + public void QueryType_IsSetCorrectly() + { + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), typeof(IEnumerable)); + Assert.Equal(typeof(PersonQuery), meta.QueryType); + } + + [Fact] + public void ServiceType_IsSetCorrectly() + { + var serviceType = typeof(object); + var meta = new QueryMeta(typeof(PersonQuery), serviceType, typeof(IEnumerable)); + Assert.Equal(serviceType, meta.ServiceType); + } + + [Fact] + public void QueryResultType_IsSetCorrectly() + { + var resultType = typeof(IEnumerable); + var meta = new QueryMeta(typeof(PersonQuery), typeof(object), resultType); + Assert.Equal(resultType, meta.QueryResultType); + } +} diff --git a/tests/Svrnty.CQRS.Tests/ServiceRegistrationTests.cs b/tests/Svrnty.CQRS.Tests/ServiceRegistrationTests.cs new file mode 100644 index 0000000..2a4d5c2 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/ServiceRegistrationTests.cs @@ -0,0 +1,180 @@ +using Microsoft.Extensions.DependencyInjection; +using Svrnty.CQRS.Abstractions; +using Svrnty.CQRS.Abstractions.Discovery; +using Svrnty.CQRS.Discovery; + +namespace Svrnty.CQRS.Tests; + +public class ServiceRegistrationTests +{ + [Fact] + public void AddCommand_WithResult_RegistersHandlerInDI() + { + var services = new ServiceCollection(); + services.AddCommand(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetService>(); + + Assert.NotNull(handler); + Assert.IsType(handler); + } + + [Fact] + public void AddCommand_WithResult_RegistersCommandMeta() + { + var services = new ServiceCollection(); + services.AddCommand(); + + 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 AddCommand_WithoutResult_RegistersHandlerInDI() + { + var services = new ServiceCollection(); + services.AddCommand(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetService>(); + + Assert.NotNull(handler); + Assert.IsType(handler); + } + + [Fact] + public void AddCommand_WithoutResult_RegistersCommandMeta() + { + var services = new ServiceCollection(); + services.AddCommand(); + + var provider = services.BuildServiceProvider(); + var metas = provider.GetServices().ToList(); + + Assert.Single(metas); + Assert.Equal(typeof(DeletePersonCommand), metas[0].CommandType); + Assert.Null(metas[0].CommandResultType); + } + + [Fact] + public void AddQuery_RegistersHandlerInDI() + { + var services = new ServiceCollection(); + services.AddQuery, PersonQueryHandler>(); + + var provider = services.BuildServiceProvider(); + var handler = provider.GetService>>(); + + Assert.NotNull(handler); + Assert.IsType(handler); + } + + [Fact] + public void AddQuery_RegistersQueryMeta() + { + var services = new ServiceCollection(); + services.AddQuery, PersonQueryHandler>(); + + var provider = services.BuildServiceProvider(); + var metas = provider.GetServices().ToList(); + + Assert.Single(metas); + Assert.Equal(typeof(PersonQuery), metas[0].QueryType); + Assert.Equal(typeof(IEnumerable), metas[0].QueryResultType); + } + + [Fact] + public void AddDefaultCommandDiscovery_RegistersCommandDiscovery() + { + var services = new ServiceCollection(); + services.AddDefaultCommandDiscovery(); + + var provider = services.BuildServiceProvider(); + var discovery = provider.GetService(); + + Assert.NotNull(discovery); + Assert.IsType(discovery); + } + + [Fact] + public void AddDefaultQueryDiscovery_RegistersQueryDiscovery() + { + var services = new ServiceCollection(); + services.AddDefaultQueryDiscovery(); + + var provider = services.BuildServiceProvider(); + var discovery = provider.GetService(); + + Assert.NotNull(discovery); + Assert.IsType(discovery); + } + + [Fact] + public void FullPipeline_DiscoveryFindsRegisteredCommands() + { + var services = new ServiceCollection(); + services.AddCommand(); + services.AddCommand(); + services.AddDefaultCommandDiscovery(); + + var provider = services.BuildServiceProvider(); + var discovery = provider.GetRequiredService(); + + Assert.Equal(2, discovery.GetCommands().Count()); + Assert.True(discovery.CommandExists("CreatePerson")); + Assert.True(discovery.CommandExists("DeletePerson")); + } + + [Fact] + public void FullPipeline_DiscoveryFindsRegisteredQueries() + { + var services = new ServiceCollection(); + services.AddQuery, PersonQueryHandler>(); + services.AddQuery(); + services.AddDefaultQueryDiscovery(); + + var provider = services.BuildServiceProvider(); + var discovery = provider.GetRequiredService(); + + Assert.Equal(2, discovery.GetQueries().Count()); + Assert.True(discovery.QueryExists("Person")); + Assert.True(discovery.QueryExists("customPersonLookup")); + } + + [Fact] + public void AddSvrntyCqrs_RegistersDiscoveryServices() + { + var services = new ServiceCollection(); + services.AddSvrntyCqrs(); + + var provider = services.BuildServiceProvider(); + + Assert.NotNull(provider.GetService()); + Assert.NotNull(provider.GetService()); + } + + [Fact] + public void AddSvrntyCqrs_WithFluentBuilder_RegistersCommandsAndQueries() + { + var services = new ServiceCollection(); + services.AddSvrntyCqrs(builder => + { + builder + .AddCommand() + .AddCommand() + .AddQuery, PersonQueryHandler>(); + }); + + var provider = services.BuildServiceProvider(); + var cmdDiscovery = provider.GetRequiredService(); + var qryDiscovery = provider.GetRequiredService(); + + Assert.Equal(2, cmdDiscovery.GetCommands().Count()); + Assert.Single(qryDiscovery.GetQueries()); + } +} diff --git a/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj b/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj new file mode 100644 index 0000000..d6b29b3 --- /dev/null +++ b/tests/Svrnty.CQRS.Tests/Svrnty.CQRS.Tests.csproj @@ -0,0 +1,26 @@ + + + + net10.0 + 14 + enable + enable + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + +