using FluentAssertions; using FnbEngine.Domain.AggregatesModel.RecipeAggregate; using Xunit; namespace FnbEngine.UnitTests.Domain; /// /// EN: Unit tests for Recipe aggregate behavior. /// VI: Unit tests cho hanh vi aggregate Recipe. /// public class RecipeTests { private static readonly Guid ValidShopId = Guid.NewGuid(); private static readonly Guid ValidProductId = Guid.NewGuid(); [Fact] public void Constructor_WithValidData_ShouldCreateActiveRecipe() { // Act var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", "Boil broth for 8 hours", 480); // Assert recipe.Id.Should().NotBeEmpty(); recipe.ShopId.Should().Be(ValidShopId); recipe.ProductId.Should().Be(ValidProductId); recipe.Name.Should().Be("Pho Bo"); recipe.Instructions.Should().Be("Boil broth for 8 hours"); recipe.PrepTimeMinutes.Should().Be(480); recipe.IsActive.Should().BeTrue(); recipe.Ingredients.Should().BeEmpty(); recipe.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5)); recipe.UpdatedAt.Should().BeNull(); } [Fact] public void Constructor_WithNullInstructions_ShouldAllowNull() { var recipe = new Recipe(ValidShopId, ValidProductId, "Simple Dish", null, 10); recipe.Instructions.Should().BeNull(); } [Fact] public void Update_ShouldModifyAllFields() { // Arrange var recipe = new Recipe(ValidShopId, ValidProductId, "Old Name", "Old instructions", 30); var newProductId = Guid.NewGuid(); // Act recipe.Update(newProductId, "New Name", "New instructions", 60); // Assert recipe.ProductId.Should().Be(newProductId); recipe.Name.Should().Be("New Name"); recipe.Instructions.Should().Be("New instructions"); recipe.PrepTimeMinutes.Should().Be(60); recipe.UpdatedAt.Should().NotBeNull(); } [Fact] public void AddIngredient_ShouldAppendToIngredientsList() { // Arrange var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480); // Act recipe.AddIngredient("Beef bones", 2.0m, "kg", 150_000m); recipe.AddIngredient("Rice noodles", 0.5m, "kg", 30_000m); // Assert recipe.Ingredients.Should().HaveCount(2); recipe.Ingredients[0].IngredientName.Should().Be("Beef bones"); recipe.Ingredients[0].Quantity.Should().Be(2.0m); recipe.Ingredients[0].Unit.Should().Be("kg"); recipe.Ingredients[0].CostPerUnit.Should().Be(150_000m); recipe.Ingredients[1].IngredientName.Should().Be("Rice noodles"); } [Fact] public void AddIngredient_WithInventoryItemId_ShouldSetCOGSFields() { // Arrange var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480); var inventoryItemId = Guid.NewGuid(); // Act recipe.AddIngredient("Beef", 1.0m, "kg", 200_000m, inventoryItemId, 0.3m); // Assert var ingredient = recipe.Ingredients.Single(); ingredient.InventoryItemId.Should().Be(inventoryItemId); ingredient.QuantityPerServing.Should().Be(0.3m); } [Fact] public void ClearIngredients_ShouldRemoveAll() { // Arrange var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480); recipe.AddIngredient("Beef bones", 2.0m, "kg", 150_000m); recipe.AddIngredient("Noodles", 0.5m, "kg", 30_000m); // Act recipe.ClearIngredients(); // Assert recipe.Ingredients.Should().BeEmpty(); recipe.UpdatedAt.Should().NotBeNull(); } [Fact] public void Deactivate_ShouldSetIsActiveToFalse() { // Arrange var recipe = new Recipe(ValidShopId, ValidProductId, "Pho Bo", null, 480); // Act recipe.Deactivate(); // Assert recipe.IsActive.Should().BeFalse(); recipe.UpdatedAt.Should().NotBeNull(); } }