// ============================================================ // TEST TEMPLATE (VSA Pattern — Handler + Validator) // Generated by MORPH Framework // ============================================================ using FluentAssertions; using FluentValidation; using FluentValidation.Results; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using {{pascalCase PROJECT_NAME}}.Database; using {{pascalCase PROJECT_NAME}}.Entities; using Xunit; namespace {{pascalCase PROJECT_NAME}}.Tests.Unit.Features.{{pascalCase FEATURE_NAME}}; // ============================================================ // Handler Tests // ============================================================ /// /// Unit tests for {{pascalCase FEATURE_NAME}} handlers. /// Tests handlers directly against a real ApplicationDbContext backed by /// in-memory SQLite (no mocks — DbSet is the repository, DbContext is the unit of work). /// public class {{pascalCase FEATURE_NAME}}HandlerTests : IDisposable { private readonly SqliteConnection _connection; private readonly ApplicationDbContext _db; public {{pascalCase FEATURE_NAME}}HandlerTests() { _connection = new SqliteConnection("DataSource=:memory:"); _connection.Open(); var options = new DbContextOptionsBuilder() .UseSqlite(_connection) .Options; _db = new ApplicationDbContext(options); _db.Database.EnsureCreated(); } public void Dispose() { _db.Dispose(); _connection.Dispose(); } #region Create Handler Tests [Fact] public async Task Create_HandleAsync_WithValidCommand_ReturnsSuccessResult() { // Arrange var command = new Create{{pascalCase FEATURE_NAME}}Request("Test {{pascalCase FEATURE_NAME}}"); var handler = new Create{{pascalCase FEATURE_NAME}}Handler(_db); // Act var result = await handler.HandleAsync(command, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); result.Value.Should().NotBeNull(); var persisted = await _db.Set<{{pascalCase FEATURE_NAME}}>().SingleAsync(); persisted.Name.Should().Be("Test {{pascalCase FEATURE_NAME}}"); } #endregion #region GetById Handler Tests [Fact] public async Task GetById_HandleAsync_WithValidId_ReturnsSuccessResult() { // Arrange var entity = CreateTestEntity("Test {{pascalCase FEATURE_NAME}}"); _db.Set<{{pascalCase FEATURE_NAME}}>().Add(entity); await _db.SaveChangesAsync(); var query = new Get{{pascalCase FEATURE_NAME}}ByIdRequest(entity.Id); var handler = new Get{{pascalCase FEATURE_NAME}}ByIdHandler(_db); // Act var result = await handler.HandleAsync(query, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); result.Value.Should().NotBeNull(); result.Value!.Name.Should().Be("Test {{pascalCase FEATURE_NAME}}"); } [Fact] public async Task GetById_HandleAsync_WithInvalidId_ReturnsFailureResult() { // Arrange var query = new Get{{pascalCase FEATURE_NAME}}ByIdRequest(Guid.CreateVersion7()); var handler = new Get{{pascalCase FEATURE_NAME}}ByIdHandler(_db); // Act var result = await handler.HandleAsync(query, CancellationToken.None); // Assert result.IsSuccess.Should().BeFalse(); } #endregion #region Update Handler Tests [Fact] public async Task Update_HandleAsync_WithValidCommand_ReturnsSuccessResult() { // Arrange var entity = CreateTestEntity("Original Name"); _db.Set<{{pascalCase FEATURE_NAME}}>().Add(entity); await _db.SaveChangesAsync(); var command = new Update{{pascalCase FEATURE_NAME}}Request(entity.Id, "Updated Name"); var handler = new Update{{pascalCase FEATURE_NAME}}Handler(_db); // Act var result = await handler.HandleAsync(command, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); var persisted = await _db.Set<{{pascalCase FEATURE_NAME}}>().SingleAsync(x => x.Id == entity.Id); persisted.Name.Should().Be("Updated Name"); } [Fact] public async Task Update_HandleAsync_WithNonExistentId_ReturnsFailureResult() { // Arrange var command = new Update{{pascalCase FEATURE_NAME}}Request(Guid.CreateVersion7(), "Updated"); var handler = new Update{{pascalCase FEATURE_NAME}}Handler(_db); // Act var result = await handler.HandleAsync(command, CancellationToken.None); // Assert result.IsSuccess.Should().BeFalse(); } #endregion #region Delete Handler Tests [Fact] public async Task Delete_HandleAsync_WithValidId_ReturnsSuccessResult() { // Arrange var entity = CreateTestEntity("To Delete"); _db.Set<{{pascalCase FEATURE_NAME}}>().Add(entity); await _db.SaveChangesAsync(); var command = new Delete{{pascalCase FEATURE_NAME}}Request(entity.Id); var handler = new Delete{{pascalCase FEATURE_NAME}}Handler(_db); // Act var result = await handler.HandleAsync(command, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); (await _db.Set<{{pascalCase FEATURE_NAME}}>().AnyAsync(x => x.Id == entity.Id)).Should().BeFalse(); } [Fact] public async Task Delete_HandleAsync_WithNonExistentId_ReturnsFailureResult() { // Arrange var command = new Delete{{pascalCase FEATURE_NAME}}Request(Guid.CreateVersion7()); var handler = new Delete{{pascalCase FEATURE_NAME}}Handler(_db); // Act var result = await handler.HandleAsync(command, CancellationToken.None); // Assert result.IsSuccess.Should().BeFalse(); } #endregion #region Helper Methods private static {{pascalCase FEATURE_NAME}} CreateTestEntity(string name) { return new {{pascalCase FEATURE_NAME}} { Id = Guid.CreateVersion7(), Name = name, // TODO: preencher demais campos obrigatórios da entidade }; } #endregion } // ============================================================ // Validator Tests // ============================================================ /// /// Unit tests for {{pascalCase FEATURE_NAME}} validators. /// Tests FluentValidation rules using ValidateAsync. /// public class {{pascalCase FEATURE_NAME}}ValidatorTests { #region Create Validator Tests [Fact] public async Task CreateValidator_WithValidCommand_PassesValidation() { // Arrange var validator = new Create{{pascalCase FEATURE_NAME}}Validator(); var command = new Create{{pascalCase FEATURE_NAME}}Request("Valid Name"); // Act ValidationResult result = await validator.ValidateAsync(command); // Assert result.IsValid.Should().BeTrue(); result.Errors.Should().BeEmpty(); } [Theory] [InlineData("")] [InlineData(" ")] [InlineData(null)] public async Task CreateValidator_WithInvalidName_FailsValidation(string? name) { // Arrange var validator = new Create{{pascalCase FEATURE_NAME}}Validator(); var command = new Create{{pascalCase FEATURE_NAME}}Request(name!); // Act ValidationResult result = await validator.ValidateAsync(command); // Assert result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == nameof(Create{{pascalCase FEATURE_NAME}}Request.Name)); } [Fact] public async Task CreateValidator_WithNameExceedingMaxLength_FailsValidation() { // Arrange var validator = new Create{{pascalCase FEATURE_NAME}}Validator(); var command = new Create{{pascalCase FEATURE_NAME}}Request(new string('A', 201)); // Act ValidationResult result = await validator.ValidateAsync(command); // Assert result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == nameof(Create{{pascalCase FEATURE_NAME}}Request.Name)); } #endregion #region Update Validator Tests [Fact] public async Task UpdateValidator_WithValidCommand_PassesValidation() { // Arrange var validator = new Update{{pascalCase FEATURE_NAME}}Validator(); var command = new Update{{pascalCase FEATURE_NAME}}Request(Guid.CreateVersion7(), "Updated Name"); // Act ValidationResult result = await validator.ValidateAsync(command); // Assert result.IsValid.Should().BeTrue(); } [Fact] public async Task UpdateValidator_WithInvalidId_FailsValidation() { // Arrange var validator = new Update{{pascalCase FEATURE_NAME}}Validator(); var command = new Update{{pascalCase FEATURE_NAME}}Request(Guid.Empty, "Updated Name"); // Act ValidationResult result = await validator.ValidateAsync(command); // Assert result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == nameof(Update{{pascalCase FEATURE_NAME}}Request.Id)); } #endregion }