diff --git a/services/booking-service-net/tests/BookingService.FunctionalTests/Controllers/ResourcesControllerTests.cs b/services/booking-service-net/tests/BookingService.FunctionalTests/Controllers/ResourcesControllerTests.cs new file mode 100644 index 00000000..1958f56c --- /dev/null +++ b/services/booking-service-net/tests/BookingService.FunctionalTests/Controllers/ResourcesControllerTests.cs @@ -0,0 +1,43 @@ +using System.Net; +using FluentAssertions; +using Microsoft.AspNetCore.Mvc.Testing; +using Xunit; + +namespace BookingService.FunctionalTests.Controllers; + +/// +/// EN: Functional tests for booking resource endpoints. +/// VI: Functional tests cho endpoint tài nguyên đặt lịch. +/// +public class ResourcesControllerTests : IClassFixture +{ + private readonly HttpClient _client; + + public ResourcesControllerTests(CustomWebApplicationFactory factory) + { + _client = factory.CreateClient(new WebApplicationFactoryClientOptions + { + AllowAutoRedirect = false, + }); + } + + [Fact] + public async Task GetResources_ShouldReturnOk() + { + // Act + var response = await _client.GetAsync($"/api/v1/resources?shopId={Guid.NewGuid()}"); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + + [Fact] + public async Task HealthCheck_ShouldReturnHealthy() + { + // Act + var response = await _client.GetAsync("/health/live"); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + } +} diff --git a/services/booking-service-net/tests/BookingService.FunctionalTests/Controllers/SamplesControllerTests.cs b/services/booking-service-net/tests/BookingService.FunctionalTests/Controllers/SamplesControllerTests.cs deleted file mode 100644 index e5a2bfe6..00000000 --- a/services/booking-service-net/tests/BookingService.FunctionalTests/Controllers/SamplesControllerTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Net; -using System.Net.Http.Json; -using FluentAssertions; -using Microsoft.AspNetCore.Mvc.Testing; -using Xunit; - -namespace BookingService.FunctionalTests.Controllers; - -/// -/// EN: Functional tests for Samples API endpoints. -/// VI: Functional tests cho các endpoints API Samples. -/// -public class SamplesControllerTests : IClassFixture -{ - private readonly HttpClient _client; - - public SamplesControllerTests(CustomWebApplicationFactory factory) - { - _client = factory.CreateClient(new WebApplicationFactoryClientOptions - { - AllowAutoRedirect = false - }); - } - - [Fact] - public async Task GetSamples_ShouldReturnOkWithEmptyList() - { - // Act - var response = await _client.GetAsync("/api/v1/samples"); - - // Assert - response.StatusCode.Should().Be(HttpStatusCode.OK); - var content = await response.Content.ReadFromJsonAsync>>(); - content?.Success.Should().BeTrue(); - } - - [Fact] - public async Task CreateSample_WithValidData_ShouldReturnCreated() - { - // Arrange - var request = new { Name = "Test Sample", Description = "Test Description" }; - - // Act - var response = await _client.PostAsJsonAsync("/api/v1/samples", request); - - // Assert - response.StatusCode.Should().Be(HttpStatusCode.Created); - var content = await response.Content.ReadFromJsonAsync>(); - content?.Success.Should().BeTrue(); - content?.Data?.Id.Should().NotBeEmpty(); - } - - [Fact] - public async Task GetSample_WithInvalidId_ShouldReturnNotFound() - { - // Arrange - var invalidId = Guid.NewGuid(); - - // Act - var response = await _client.GetAsync($"/api/v1/samples/{invalidId}"); - - // Assert - response.StatusCode.Should().Be(HttpStatusCode.NotFound); - } - - [Fact] - public async Task HealthCheck_ShouldReturnHealthy() - { - // Act - var response = await _client.GetAsync("/health/live"); - - // Assert - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - - // EN: Helper DTOs for deserialization - // VI: Helper DTOs để deserialize - private record ApiResponse(bool Success, T? Data); - private record CreateSampleResult(Guid Id); -} diff --git a/services/booking-service-net/tests/BookingService.UnitTests/Application/CreateSampleCommandHandlerTests.cs b/services/booking-service-net/tests/BookingService.UnitTests/Application/CreateSampleCommandHandlerTests.cs deleted file mode 100644 index 0e10b430..00000000 --- a/services/booking-service-net/tests/BookingService.UnitTests/Application/CreateSampleCommandHandlerTests.cs +++ /dev/null @@ -1,65 +0,0 @@ -using FluentAssertions; -using Microsoft.Extensions.Logging; -using Moq; -using BookingService.API.Application.Commands; -using BookingService.Domain.AggregatesModel.SampleAggregate; -using BookingService.Domain.SeedWork; -using Xunit; - -namespace BookingService.UnitTests.Application; - -/// -/// EN: Unit tests for CreateSampleCommandHandler. -/// VI: Unit tests cho CreateSampleCommandHandler. -/// -public class CreateSampleCommandHandlerTests -{ - private readonly Mock _mockRepository; - private readonly Mock> _mockLogger; - private readonly CreateSampleCommandHandler _handler; - - public CreateSampleCommandHandlerTests() - { - _mockRepository = new Mock(); - _mockLogger = new Mock>(); - - var mockUnitOfWork = new Mock(); - mockUnitOfWork.Setup(u => u.SaveEntitiesAsync(It.IsAny())) - .ReturnsAsync(true); - - _mockRepository.SetupGet(r => r.UnitOfWork).Returns(mockUnitOfWork.Object); - - _handler = new CreateSampleCommandHandler(_mockRepository.Object, _mockLogger.Object); - } - - [Fact] - public async Task Handle_WithValidCommand_ShouldCreateSampleAndReturnId() - { - // Arrange - var command = new CreateSampleCommand("Test Sample", "Test Description"); - - _mockRepository.Setup(r => r.Add(It.IsAny())) - .Returns((Sample s) => s); - - // Act - var result = await _handler.Handle(command, CancellationToken.None); - - // Assert - result.Should().NotBeNull(); - result.Id.Should().NotBeEmpty(); - _mockRepository.Verify(r => r.Add(It.IsAny()), Times.Once); - } - - [Fact] - public async Task Handle_WithValidCommand_ShouldCallSaveEntities() - { - // Arrange - var command = new CreateSampleCommand("Test Sample", null); - - // Act - await _handler.Handle(command, CancellationToken.None); - - // Assert - _mockRepository.Verify(r => r.UnitOfWork.SaveEntitiesAsync(It.IsAny()), Times.Once); - } -} diff --git a/services/booking-service-net/tests/BookingService.UnitTests/Domain/AppointmentAggregateTests.cs b/services/booking-service-net/tests/BookingService.UnitTests/Domain/AppointmentAggregateTests.cs new file mode 100644 index 00000000..8fdb95c9 --- /dev/null +++ b/services/booking-service-net/tests/BookingService.UnitTests/Domain/AppointmentAggregateTests.cs @@ -0,0 +1,68 @@ +using FluentAssertions; +using BookingService.Domain.AggregatesModel.AppointmentAggregate; +using BookingService.Domain.Exceptions; +using Xunit; + +namespace BookingService.UnitTests.Domain; + +/// +/// EN: Unit tests for appointment aggregate behavior. +/// VI: Unit tests cho hành vi aggregate cuộc hẹn. +/// +public class AppointmentAggregateTests +{ + [Fact] + public void CreateAppointment_ShouldInitializeAsScheduled() + { + // Act + var appointment = new Appointment( + Guid.NewGuid(), + Guid.NewGuid(), + DateTime.UtcNow.AddHours(1), + DateTime.UtcNow.AddHours(2), + Guid.NewGuid()); + + // Assert + appointment.Status.Should().Be("Scheduled"); + appointment.Id.Should().NotBeEmpty(); + } + + [Fact] + public void Complete_AfterConfirmAndStart_ShouldSetCompleted() + { + // Arrange + var appointment = new Appointment( + Guid.NewGuid(), + Guid.NewGuid(), + DateTime.UtcNow.AddHours(2), + DateTime.UtcNow.AddHours(3)); + appointment.Confirm(); + appointment.MarkAsInProgress(); + + // Act + appointment.Complete(); + + // Assert + appointment.Status.Should().Be("Completed"); + } + + [Fact] + public void Cancel_WhenCompleted_ShouldThrowDomainException() + { + // Arrange + var appointment = new Appointment( + Guid.NewGuid(), + Guid.NewGuid(), + DateTime.UtcNow.AddHours(2), + DateTime.UtcNow.AddHours(3)); + appointment.Confirm(); + appointment.MarkAsInProgress(); + appointment.Complete(); + + // Act + var action = () => appointment.Cancel("Customer requested"); + + // Assert + action.Should().Throw(); + } +} diff --git a/services/booking-service-net/tests/BookingService.UnitTests/Domain/SampleAggregateTests.cs b/services/booking-service-net/tests/BookingService.UnitTests/Domain/SampleAggregateTests.cs deleted file mode 100644 index 3b3081d4..00000000 --- a/services/booking-service-net/tests/BookingService.UnitTests/Domain/SampleAggregateTests.cs +++ /dev/null @@ -1,151 +0,0 @@ -using FluentAssertions; -using BookingService.Domain.AggregatesModel.SampleAggregate; -using BookingService.Domain.Exceptions; -using Xunit; - -namespace BookingService.UnitTests.Domain; - -/// -/// EN: Unit tests for Sample aggregate. -/// VI: Unit tests cho Sample aggregate. -/// -public class SampleAggregateTests -{ - [Fact] - public void CreateSample_WithValidName_ShouldCreateWithDraftStatus() - { - // Arrange - var name = "Test Sample"; - var description = "Test Description"; - - // Act - var sample = new Sample(name, description); - - // Assert - sample.Name.Should().Be(name); - sample.Description.Should().Be(description); - sample.Status.Should().Be(SampleStatus.Draft); - sample.Id.Should().NotBeEmpty(); - sample.DomainEvents.Should().ContainSingle(); // SampleCreatedDomainEvent - } - - [Fact] - public void CreateSample_WithEmptyName_ShouldThrowException() - { - // Arrange - var name = ""; - - // Act - var act = () => new Sample(name); - - // Assert - act.Should().Throw() - .WithMessage("Sample name cannot be empty"); - } - - [Fact] - public void Activate_WhenDraft_ShouldChangeToActive() - { - // Arrange - var sample = new Sample("Test Sample"); - sample.ClearDomainEvents(); - - // Act - sample.Activate(); - - // Assert - sample.Status.Should().Be(SampleStatus.Active); - sample.DomainEvents.Should().ContainSingle(); // SampleStatusChangedDomainEvent - } - - [Fact] - public void Activate_WhenNotDraft_ShouldThrowException() - { - // Arrange - var sample = new Sample("Test Sample"); - sample.Activate(); - - // Act - var act = () => sample.Activate(); - - // Assert - act.Should().Throw() - .WithMessage("Only draft samples can be activated"); - } - - [Fact] - public void Complete_WhenActive_ShouldChangeToCompleted() - { - // Arrange - var sample = new Sample("Test Sample"); - sample.Activate(); - sample.ClearDomainEvents(); - - // Act - sample.Complete(); - - // Assert - sample.Status.Should().Be(SampleStatus.Completed); - } - - [Fact] - public void Cancel_WhenDraftOrActive_ShouldChangeToCancelled() - { - // Arrange - var sample = new Sample("Test Sample"); - - // Act - sample.Cancel(); - - // Assert - sample.Status.Should().Be(SampleStatus.Cancelled); - } - - [Fact] - public void Cancel_WhenCompleted_ShouldThrowException() - { - // Arrange - var sample = new Sample("Test Sample"); - sample.Activate(); - sample.Complete(); - - // Act - var act = () => sample.Cancel(); - - // Assert - act.Should().Throw() - .WithMessage("Cannot cancel a completed sample"); - } - - [Fact] - public void Update_WhenNotCancelled_ShouldUpdateNameAndDescription() - { - // Arrange - var sample = new Sample("Original Name", "Original Description"); - var newName = "Updated Name"; - var newDescription = "Updated Description"; - - // Act - sample.Update(newName, newDescription); - - // Assert - sample.Name.Should().Be(newName); - sample.Description.Should().Be(newDescription); - sample.UpdatedAt.Should().NotBeNull(); - } - - [Fact] - public void Update_WhenCancelled_ShouldThrowException() - { - // Arrange - var sample = new Sample("Test Sample"); - sample.Cancel(); - - // Act - var act = () => sample.Update("New Name", null); - - // Assert - act.Should().Throw() - .WithMessage("Cannot update a cancelled sample"); - } -}