diff --git a/services/catalog-service-net/tests/CatalogService.FunctionalTests/Controllers/ProductsControllerTests.cs b/services/catalog-service-net/tests/CatalogService.FunctionalTests/Controllers/ProductsControllerTests.cs
new file mode 100644
index 00000000..efedc6f1
--- /dev/null
+++ b/services/catalog-service-net/tests/CatalogService.FunctionalTests/Controllers/ProductsControllerTests.cs
@@ -0,0 +1,53 @@
+using System.Net;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Xunit;
+
+namespace CatalogService.FunctionalTests.Controllers;
+
+///
+/// EN: Functional tests for product endpoints.
+/// VI: Functional tests cho endpoint sản phẩm.
+///
+public class ProductsControllerTests : IClassFixture
+{
+ private readonly HttpClient _client;
+
+ public ProductsControllerTests(CustomWebApplicationFactory factory)
+ {
+ _client = factory.CreateClient(new WebApplicationFactoryClientOptions
+ {
+ AllowAutoRedirect = false,
+ });
+ }
+
+ [Fact]
+ public async Task GetProducts_ShouldReturnOk()
+ {
+ // Act
+ var response = await _client.GetAsync($"/api/v1/products?shopId={Guid.NewGuid()}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+ }
+
+ [Fact]
+ public async Task GetProduct_WithUnknownId_ShouldReturnNotFound()
+ {
+ // Act
+ var response = await _client.GetAsync($"/api/v1/products/{Guid.NewGuid()}");
+
+ // 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);
+ }
+}
diff --git a/services/catalog-service-net/tests/CatalogService.FunctionalTests/Controllers/SamplesControllerTests.cs b/services/catalog-service-net/tests/CatalogService.FunctionalTests/Controllers/SamplesControllerTests.cs
deleted file mode 100644
index b701e25b..00000000
--- a/services/catalog-service-net/tests/CatalogService.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 CatalogService.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/catalog-service-net/tests/CatalogService.UnitTests/Domain/ProductAggregateTests.cs b/services/catalog-service-net/tests/CatalogService.UnitTests/Domain/ProductAggregateTests.cs
new file mode 100644
index 00000000..7152356e
--- /dev/null
+++ b/services/catalog-service-net/tests/CatalogService.UnitTests/Domain/ProductAggregateTests.cs
@@ -0,0 +1,54 @@
+using FluentAssertions;
+using CatalogService.Domain.AggregatesModel.ProductAggregate;
+using CatalogService.Domain.Exceptions;
+using Xunit;
+
+namespace CatalogService.UnitTests.Domain;
+
+///
+/// EN: Unit tests for product aggregate behavior.
+/// VI: Unit tests cho hành vi aggregate sản phẩm.
+///
+public class ProductAggregateTests
+{
+ [Fact]
+ public void CreateProduct_WithValidData_ShouldBeActive()
+ {
+ // Act
+ var product = new Product(Guid.NewGuid(), "Cà phê sữa", 35000m, ProductType.PreparedFood);
+
+ // Assert
+ product.Name.Should().Be("Cà phê sữa");
+ product.Price.Should().Be(35000m);
+ product.Type.Should().Be(ProductType.PreparedFood);
+ product.IsActive.Should().BeTrue();
+ }
+
+ [Fact]
+ public void UpdateInfo_ShouldUpdateNameAndPrice()
+ {
+ // Arrange
+ var product = new Product(Guid.NewGuid(), "Trà đào", 30000m, ProductType.PreparedFood);
+
+ // Act
+ product.UpdateInfo("Trà đào cam sả", "Best seller", 42000m);
+
+ // Assert
+ product.Name.Should().Be("Trà đào cam sả");
+ product.Description.Should().Be("Best seller");
+ product.Price.Should().Be(42000m);
+ }
+
+ [Fact]
+ public void Activate_WhenAlreadyActive_ShouldThrowDomainException()
+ {
+ // Arrange
+ var product = new Product(Guid.NewGuid(), "Combo lunch", 89000m, ProductType.Physical);
+
+ // Act
+ var action = () => product.Activate();
+
+ // Assert
+ action.Should().Throw();
+ }
+}
diff --git a/services/catalog-service-net/tests/CatalogService.UnitTests/Domain/SampleAggregateTests.cs b/services/catalog-service-net/tests/CatalogService.UnitTests/Domain/SampleAggregateTests.cs
deleted file mode 100644
index 26218e25..00000000
--- a/services/catalog-service-net/tests/CatalogService.UnitTests/Domain/SampleAggregateTests.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using FluentAssertions;
-using CatalogService.Domain.AggregatesModel.SampleAggregate;
-using CatalogService.Domain.Exceptions;
-using Xunit;
-
-namespace CatalogService.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");
- }
-}
diff --git a/services/fnb-engine-net/tests/FnbEngine.FunctionalTests/Controllers/SamplesControllerTests.cs b/services/fnb-engine-net/tests/FnbEngine.FunctionalTests/Controllers/SamplesControllerTests.cs
deleted file mode 100644
index cee049f7..00000000
--- a/services/fnb-engine-net/tests/FnbEngine.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 FnbEngine.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/fnb-engine-net/tests/FnbEngine.FunctionalTests/Controllers/TablesControllerTests.cs b/services/fnb-engine-net/tests/FnbEngine.FunctionalTests/Controllers/TablesControllerTests.cs
new file mode 100644
index 00000000..fd5b8d0c
--- /dev/null
+++ b/services/fnb-engine-net/tests/FnbEngine.FunctionalTests/Controllers/TablesControllerTests.cs
@@ -0,0 +1,43 @@
+using System.Net;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Xunit;
+
+namespace FnbEngine.FunctionalTests.Controllers;
+
+///
+/// EN: Functional tests for table management endpoints.
+/// VI: Functional tests cho endpoint quản lý bàn.
+///
+public class TablesControllerTests : IClassFixture
+{
+ private readonly HttpClient _client;
+
+ public TablesControllerTests(CustomWebApplicationFactory factory)
+ {
+ _client = factory.CreateClient(new WebApplicationFactoryClientOptions
+ {
+ AllowAutoRedirect = false,
+ });
+ }
+
+ [Fact]
+ public async Task GetTables_ShouldReturnOk()
+ {
+ // Act
+ var response = await _client.GetAsync($"/api/v1/tables?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/fnb-engine-net/tests/FnbEngine.UnitTests/Application/CreateSampleCommandHandlerTests.cs b/services/fnb-engine-net/tests/FnbEngine.UnitTests/Application/CreateSampleCommandHandlerTests.cs
deleted file mode 100644
index 78373e3a..00000000
--- a/services/fnb-engine-net/tests/FnbEngine.UnitTests/Application/CreateSampleCommandHandlerTests.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using FluentAssertions;
-using Microsoft.Extensions.Logging;
-using Moq;
-using FnbEngine.API.Application.Commands;
-using FnbEngine.Domain.AggregatesModel.SampleAggregate;
-using FnbEngine.Domain.SeedWork;
-using Xunit;
-
-namespace FnbEngine.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/fnb-engine-net/tests/FnbEngine.UnitTests/Domain/SampleAggregateTests.cs b/services/fnb-engine-net/tests/FnbEngine.UnitTests/Domain/SampleAggregateTests.cs
deleted file mode 100644
index 4860add7..00000000
--- a/services/fnb-engine-net/tests/FnbEngine.UnitTests/Domain/SampleAggregateTests.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using FluentAssertions;
-using FnbEngine.Domain.AggregatesModel.SampleAggregate;
-using FnbEngine.Domain.Exceptions;
-using Xunit;
-
-namespace FnbEngine.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");
- }
-}
diff --git a/services/fnb-engine-net/tests/FnbEngine.UnitTests/Domain/TableAggregateTests.cs b/services/fnb-engine-net/tests/FnbEngine.UnitTests/Domain/TableAggregateTests.cs
new file mode 100644
index 00000000..a12ff68b
--- /dev/null
+++ b/services/fnb-engine-net/tests/FnbEngine.UnitTests/Domain/TableAggregateTests.cs
@@ -0,0 +1,52 @@
+using FluentAssertions;
+using FnbEngine.Domain.AggregatesModel.TableAggregate;
+using FnbEngine.Domain.Exceptions;
+using Xunit;
+
+namespace FnbEngine.UnitTests.Domain;
+
+///
+/// EN: Unit tests for table aggregate behavior.
+/// VI: Unit tests cho hành vi aggregate bàn ăn.
+///
+public class TableAggregateTests
+{
+ [Fact]
+ public void CreateTable_WithValidData_ShouldBeAvailable()
+ {
+ // Act
+ var table = new Table(Guid.NewGuid(), "A-01", 4, "Main Hall");
+
+ // Assert
+ table.TableNumber.Should().Be("A-01");
+ table.Capacity.Should().Be(4);
+ table.Status.Should().Be(TableStatus.Available);
+ }
+
+ [Fact]
+ public void MarkAsOccupied_WhenAvailable_ShouldSucceed()
+ {
+ // Arrange
+ var table = new Table(Guid.NewGuid(), "B-02", 6);
+
+ // Act
+ table.MarkAsOccupied();
+
+ // Assert
+ table.Status.Should().Be(TableStatus.Occupied);
+ }
+
+ [Fact]
+ public void MarkAsOccupied_WhenCleaning_ShouldThrowDomainException()
+ {
+ // Arrange
+ var table = new Table(Guid.NewGuid(), "C-03", 2);
+ table.MarkAsCleaning();
+
+ // Act
+ var action = () => table.MarkAsOccupied();
+
+ // Assert
+ action.Should().Throw();
+ }
+}
diff --git a/services/mkt-x-service-net/tests/MktXService.FunctionalTests/Controllers/AccountsControllerTests.cs b/services/mkt-x-service-net/tests/MktXService.FunctionalTests/Controllers/AccountsControllerTests.cs
new file mode 100644
index 00000000..ec54d9b4
--- /dev/null
+++ b/services/mkt-x-service-net/tests/MktXService.FunctionalTests/Controllers/AccountsControllerTests.cs
@@ -0,0 +1,53 @@
+using System.Net;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Xunit;
+
+namespace MktXService.FunctionalTests.Controllers;
+
+///
+/// EN: Functional tests for X account endpoints.
+/// VI: Functional tests cho endpoint tài khoản X.
+///
+public class AccountsControllerTests : IClassFixture
+{
+ private readonly HttpClient _client;
+
+ public AccountsControllerTests(CustomWebApplicationFactory factory)
+ {
+ _client = factory.CreateClient(new WebApplicationFactoryClientOptions
+ {
+ AllowAutoRedirect = false,
+ });
+ }
+
+ [Fact]
+ public async Task GetAccounts_ShouldReturnOk()
+ {
+ // Act
+ var response = await _client.GetAsync($"/api/v1/accounts?merchantId={Guid.NewGuid()}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+ }
+
+ [Fact]
+ public async Task GetAccount_WithUnknownId_ShouldReturnNotFound()
+ {
+ // Act
+ var response = await _client.GetAsync($"/api/v1/accounts/{Guid.NewGuid()}");
+
+ // 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);
+ }
+}
diff --git a/services/mkt-x-service-net/tests/MktXService.FunctionalTests/Controllers/SamplesControllerTests.cs b/services/mkt-x-service-net/tests/MktXService.FunctionalTests/Controllers/SamplesControllerTests.cs
deleted file mode 100644
index d7d55277..00000000
--- a/services/mkt-x-service-net/tests/MktXService.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 MktXService.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/mkt-x-service-net/tests/MktXService.UnitTests/Application/CreateSampleCommandHandlerTests.cs b/services/mkt-x-service-net/tests/MktXService.UnitTests/Application/CreateSampleCommandHandlerTests.cs
deleted file mode 100644
index e7fd2291..00000000
--- a/services/mkt-x-service-net/tests/MktXService.UnitTests/Application/CreateSampleCommandHandlerTests.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using FluentAssertions;
-using Microsoft.Extensions.Logging;
-using Moq;
-using MktXService.API.Application.Commands;
-using MktXService.Domain.AggregatesModel.SampleAggregate;
-using MktXService.Domain.SeedWork;
-using Xunit;
-
-namespace MktXService.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/mkt-x-service-net/tests/MktXService.UnitTests/Domain/SampleAggregateTests.cs b/services/mkt-x-service-net/tests/MktXService.UnitTests/Domain/SampleAggregateTests.cs
deleted file mode 100644
index 96c63b66..00000000
--- a/services/mkt-x-service-net/tests/MktXService.UnitTests/Domain/SampleAggregateTests.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using FluentAssertions;
-using MktXService.Domain.AggregatesModel.SampleAggregate;
-using MktXService.Domain.Exceptions;
-using Xunit;
-
-namespace MktXService.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");
- }
-}
diff --git a/services/mkt-x-service-net/tests/MktXService.UnitTests/Domain/TwitterAccountAggregateTests.cs b/services/mkt-x-service-net/tests/MktXService.UnitTests/Domain/TwitterAccountAggregateTests.cs
new file mode 100644
index 00000000..869bb57c
--- /dev/null
+++ b/services/mkt-x-service-net/tests/MktXService.UnitTests/Domain/TwitterAccountAggregateTests.cs
@@ -0,0 +1,66 @@
+using FluentAssertions;
+using MktXService.Domain.AggregatesModel.TwitterAccountAggregate;
+using MktXService.Domain.Exceptions;
+using Xunit;
+
+namespace MktXService.UnitTests.Domain;
+
+///
+/// EN: Unit tests for Twitter account aggregate behavior.
+/// VI: Unit tests cho hành vi aggregate tài khoản Twitter.
+///
+public class TwitterAccountAggregateTests
+{
+ [Fact]
+ public void CreateAccount_ShouldStartInPendingStatus()
+ {
+ // Act
+ var account = new TwitterAccount(
+ Guid.NewGuid(),
+ "twitter-user-1",
+ "goodgo_user",
+ "encrypted-token",
+ "encrypted-secret");
+
+ // Assert
+ account.Status.Should().Be(TwitterAccountStatus.Pending);
+ account.OAuthToken.Should().Be("encrypted-token");
+ }
+
+ [Fact]
+ public void Activate_ShouldMoveStatusToActive()
+ {
+ // Arrange
+ var account = new TwitterAccount(
+ Guid.NewGuid(),
+ "twitter-user-2",
+ "goodgo_user2",
+ "token",
+ "secret");
+
+ // Act
+ account.Activate();
+
+ // Assert
+ account.Status.Should().Be(TwitterAccountStatus.Active);
+ }
+
+ [Fact]
+ public void Activate_WhenDisconnected_ShouldThrowDomainException()
+ {
+ // Arrange
+ var account = new TwitterAccount(
+ Guid.NewGuid(),
+ "twitter-user-3",
+ "goodgo_user3",
+ "token",
+ "secret");
+ account.Disconnect();
+
+ // Act
+ var action = () => account.Activate();
+
+ // Assert
+ action.Should().Throw();
+ }
+}
diff --git a/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Application/CreateSampleCommandHandlerTests.cs b/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Application/CreateSampleCommandHandlerTests.cs
deleted file mode 100644
index e821d35a..00000000
--- a/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Application/CreateSampleCommandHandlerTests.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using FluentAssertions;
-using Microsoft.Extensions.Logging;
-using Moq;
-using MktZaloService.API.Application.Commands;
-using MktZaloService.Domain.AggregatesModel.SampleAggregate;
-using MktZaloService.Domain.SeedWork;
-using Xunit;
-
-namespace MktZaloService.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/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Domain/ConversationAggregateTests.cs b/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Domain/ConversationAggregateTests.cs
new file mode 100644
index 00000000..61b9d780
--- /dev/null
+++ b/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Domain/ConversationAggregateTests.cs
@@ -0,0 +1,56 @@
+using FluentAssertions;
+using MktZaloService.Domain.AggregatesModel.ConversationAggregate;
+using MktZaloService.Domain.Enums;
+using MktZaloService.Domain.Exceptions;
+using Xunit;
+
+namespace MktZaloService.UnitTests.Domain;
+
+///
+/// EN: Unit tests for conversation aggregate behavior.
+/// VI: Unit tests cho hành vi aggregate conversation.
+///
+public class ConversationAggregateTests
+{
+ [Fact]
+ public void CreateConversation_ShouldInitializeAsActive()
+ {
+ // Act
+ var conversation = new Conversation("zalo-user-1", Guid.NewGuid());
+
+ // Assert
+ conversation.Status.Should().Be(ConversationStatus.Active);
+ conversation.MessageCount.Should().Be(0);
+ conversation.EndedAt.Should().BeNull();
+ }
+
+ [Fact]
+ public void AddMessage_ShouldIncreaseCountAndUpdatePreview()
+ {
+ // Arrange
+ var conversation = new Conversation("zalo-user-2", Guid.NewGuid());
+
+ // Act
+ var message = conversation.AddMessage(MessageType.Text, "Xin chào Zalo", MessageDirection.Incoming, false);
+
+ // Assert
+ message.Should().NotBeNull();
+ conversation.MessageCount.Should().Be(1);
+ conversation.LastMessagePreview.Should().Be("Xin chào Zalo");
+ conversation.LastMessageAt.Should().NotBeNull();
+ }
+
+ [Fact]
+ public void AddMessage_WhenClosed_ShouldThrowConversationClosedException()
+ {
+ // Arrange
+ var conversation = new Conversation("zalo-user-3", Guid.NewGuid());
+ conversation.Close();
+
+ // Act
+ var action = () => conversation.AddMessage(MessageType.Text, "Should fail", MessageDirection.Incoming, false);
+
+ // Assert
+ action.Should().Throw();
+ }
+}
diff --git a/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Domain/SampleAggregateTests.cs b/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Domain/SampleAggregateTests.cs
deleted file mode 100644
index 68d4c30b..00000000
--- a/services/mkt-zalo-service-net/tests/MktZaloService.UnitTests/Domain/SampleAggregateTests.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using FluentAssertions;
-using MktZaloService.Domain.AggregatesModel.SampleAggregate;
-using MktZaloService.Domain.Exceptions;
-using Xunit;
-
-namespace MktZaloService.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");
- }
-}
diff --git a/services/mkt-zalo-service-net/tests/MyService.FunctionalTests/Controllers/ConversationsControllerTests.cs b/services/mkt-zalo-service-net/tests/MyService.FunctionalTests/Controllers/ConversationsControllerTests.cs
new file mode 100644
index 00000000..fc4a6288
--- /dev/null
+++ b/services/mkt-zalo-service-net/tests/MyService.FunctionalTests/Controllers/ConversationsControllerTests.cs
@@ -0,0 +1,43 @@
+using System.Net;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Xunit;
+
+namespace MktZaloService.FunctionalTests.Controllers;
+
+///
+/// EN: Functional tests for Zalo conversations endpoints.
+/// VI: Functional tests cho endpoint hội thoại Zalo.
+///
+public class ConversationsControllerTests : IClassFixture
+{
+ private readonly HttpClient _client;
+
+ public ConversationsControllerTests(CustomWebApplicationFactory factory)
+ {
+ _client = factory.CreateClient(new WebApplicationFactoryClientOptions
+ {
+ AllowAutoRedirect = false,
+ });
+ }
+
+ [Fact]
+ public async Task GetConversation_WithoutAuthentication_ShouldReturnUnauthorized()
+ {
+ // Act
+ var response = await _client.GetAsync($"/api/v1/conversations/{Guid.NewGuid()}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
+ }
+
+ [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/mkt-zalo-service-net/tests/MyService.FunctionalTests/Controllers/SamplesControllerTests.cs b/services/mkt-zalo-service-net/tests/MyService.FunctionalTests/Controllers/SamplesControllerTests.cs
deleted file mode 100644
index 4523df67..00000000
--- a/services/mkt-zalo-service-net/tests/MyService.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 MktZaloService.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);
-}