From 3ed0ce275bb1ce0323735865240c1c6a286e0237 Mon Sep 17 00:00:00 2001 From: Gerrit-Jan Lubbertsen Date: Mon, 11 Nov 2024 14:24:23 +0100 Subject: [PATCH 1/2] Add PizzaValidator --- .../Extensions/ServiceCollectionExtensions.cs | 1 + .../PizzaService.cs | 40 ++-------------- .../PizzaValidator.cs | 45 ++++++++++++++++++ .../PizzaServiceTest.cs | 47 +++++++++++++++++++ 4 files changed, 98 insertions(+), 35 deletions(-) create mode 100644 src/Backend/Contoso.Pizza.AdminApi.Services/PizzaValidator.cs create mode 100644 src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs diff --git a/src/Backend/Contoso.Pizza.AdminApi.Services/Extensions/ServiceCollectionExtensions.cs b/src/Backend/Contoso.Pizza.AdminApi.Services/Extensions/ServiceCollectionExtensions.cs index 546b501..3847731 100644 --- a/src/Backend/Contoso.Pizza.AdminApi.Services/Extensions/ServiceCollectionExtensions.cs +++ b/src/Backend/Contoso.Pizza.AdminApi.Services/Extensions/ServiceCollectionExtensions.cs @@ -19,6 +19,7 @@ public static IServiceCollection AddContosoPizzaServices(this IServiceCollection services.AddScoped(); services.AddSingleton(s => TimeProvider.System); services.AddSingleton(); + services.AddScoped(); services.AddScoped(); return services; } diff --git a/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaService.cs b/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaService.cs index ca1fda9..0bb0147 100644 --- a/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaService.cs +++ b/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaService.cs @@ -8,13 +8,13 @@ namespace Contoso.Pizza.AdminApi.Services; public class PizzaService : IPizzaService { - private readonly IPriceCalculatorService _priceCalculatorService; + private readonly IPizzaValidator _pizzaValidator; private readonly IPizzaRepository _repository; private readonly IMapper _mapper; - public PizzaService(IPriceCalculatorService priceCalculatorService, IPizzaRepository repository, IMapper mapper) + public PizzaService(IPizzaValidator pizzaValidator, IPizzaRepository repository, IMapper mapper) { - _priceCalculatorService = priceCalculatorService; + _pizzaValidator = pizzaValidator; _repository = repository; _mapper = mapper; } @@ -33,7 +33,7 @@ public async Task> GetAllAsync() public async Task AddAsync(PizzaEntity entity) { - var validationErrors = await IsValidPizza(entity); + var validationErrors = await _pizzaValidator.IsValidPizza(entity); if (validationErrors.Count != 0) { throw new ArgumentException(string.Join("; ", validationErrors)); @@ -45,7 +45,7 @@ public async Task AddAsync(PizzaEntity entity) public async Task UpdateAsync(PizzaEntity entity) { - var validationErrors = await IsValidPizza(entity); + var validationErrors = await _pizzaValidator.IsValidPizza(entity); if (validationErrors.Count != 0) { throw new ArgumentException(string.Join("; ", validationErrors)); @@ -58,34 +58,4 @@ public async Task DeleteAsync(Guid id) { return await _repository.DeleteAsync(id); } - - private async Task> IsValidPizza(PizzaEntity pizza) - { - var validationErrors = new List(); - - if (string.IsNullOrWhiteSpace(pizza.Name)) - { - validationErrors.Add("Pizza name cannot be empty."); - } - - if (pizza.Toppings == null || !pizza.Toppings.Any()) - { - validationErrors.Add("Pizza must have at least one topping."); - } - - var totalPrice = _priceCalculatorService.CalculatePrice(pizza); - - if (totalPrice < 5 || totalPrice > 50) - { - validationErrors.Add("Total price of the pizza must be between $5 and $50."); - } - - var existingPizzas = await _repository.GetAllAsync(); - if (existingPizzas.Any(p => p.Name.Equals(pizza.Name, StringComparison.OrdinalIgnoreCase))) - { - validationErrors.Add("Pizza name must be unique."); - } - - return validationErrors; - } } diff --git a/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaValidator.cs b/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaValidator.cs new file mode 100644 index 0000000..9e7b57c --- /dev/null +++ b/src/Backend/Contoso.Pizza.AdminApi.Services/PizzaValidator.cs @@ -0,0 +1,45 @@ +using Contoso.Pizza.AdminApi.Models; +using Contoso.Pizza.Data.Contracts; + +namespace Contoso.Pizza.AdminApi.Services; + +public interface IPizzaValidator +{ + Task> IsValidPizza(PizzaEntity pizza); +} + +public class PizzaValidator(IPriceCalculatorService priceCalculatorService, IPizzaRepository repository) : IPizzaValidator +{ + private readonly IPriceCalculatorService _priceCalculatorService = priceCalculatorService; + private readonly IPizzaRepository _repository = repository; + + public async Task> IsValidPizza(PizzaEntity pizza) + { + var validationErrors = new List(); + + if (string.IsNullOrWhiteSpace(pizza.Name)) + { + validationErrors.Add("Pizza name cannot be empty."); + } + + if (pizza.Toppings == null || !pizza.Toppings.Any()) + { + validationErrors.Add("Pizza must have at least one topping."); + } + + var totalPrice = _priceCalculatorService.CalculatePrice(pizza); + + if (totalPrice < 5 || totalPrice > 50) + { + validationErrors.Add("Total price of the pizza must be between $5 and $50."); + } + + var existingPizzas = await _repository.GetAllAsync(); + if (existingPizzas.Any(p => p.Name.Equals(pizza.Name, StringComparison.OrdinalIgnoreCase))) + { + validationErrors.Add("Pizza name must be unique."); + } + + return validationErrors; + } +} diff --git a/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs b/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs new file mode 100644 index 0000000..6c3aea9 --- /dev/null +++ b/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs @@ -0,0 +1,47 @@ +using FakeItEasy; +using FluentAssertions; +using NUnit.Framework; +using Contoso.Pizza.AdminApi.Services; +using Contoso.Pizza.Data.Contracts; +using DM = Contoso.Pizza.Data.Models; + +namespace Contoso.Pizza.AdminApi.Models; + +[TestFixture] +public class PizzaServiceTest +{ + private IPriceCalculatorService _priceCalculatorService = default!; + private IPizzaRepository _repo = default!; + private PizzaValidator _sut = default!; + + [SetUp] + public void Setup() + { + _priceCalculatorService = A.Fake(); + _repo = A.Fake(); + _sut = new PizzaValidator(_priceCalculatorService, _repo); + } + + [Test] + public async Task CalculatePrice_WithBasicPizza_ReturnsMinimumAmount() + { + A.CallTo(() => _priceCalculatorService.CalculatePrice(A._)).Returns(30); + A.CallTo(() => _repo.GetAllAsync()) + .ReturnsLazily((c) => + Task.FromResult>( + [ + new DM.Pizza{Name = "Test Pizza", Price = 2,Sauce = new() { Name = "Sauce" }} + ] + )); + + var errors = await _sut.IsValidPizza(new PizzaEntity + { + Name = "Test Pizza", + Price = 2, + Sauce = new() { Price = 1 }, + Toppings = [new () { Name = "A", Price = 2 }] + }); + errors.Should().Contain("Pizza name must be unique."); + } +} + From 9d5c1f54a4a02b50d84cc083eca2fb3d5f7e5774 Mon Sep 17 00:00:00 2001 From: Gerrit-Jan Lubbertsen Date: Mon, 11 Nov 2024 14:35:45 +0100 Subject: [PATCH 2/2] Cleanup for less hints --- .../Contoso.Pizza.Data.Tests/PizzaServiceTest.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs b/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs index 6c3aea9..388594d 100644 --- a/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs +++ b/src/Backend/Contoso.Pizza.Data.Tests/PizzaServiceTest.cs @@ -10,7 +10,7 @@ namespace Contoso.Pizza.AdminApi.Models; [TestFixture] public class PizzaServiceTest { - private IPriceCalculatorService _priceCalculatorService = default!; + private IPriceCalculatorService _priceCalculatorService = default!; private IPizzaRepository _repo = default!; private PizzaValidator _sut = default!; @@ -27,21 +27,12 @@ public async Task CalculatePrice_WithBasicPizza_ReturnsMinimumAmount() { A.CallTo(() => _priceCalculatorService.CalculatePrice(A._)).Returns(30); A.CallTo(() => _repo.GetAllAsync()) - .ReturnsLazily((c) => + .ReturnsLazily((c) => Task.FromResult>( [ new DM.Pizza{Name = "Test Pizza", Price = 2,Sauce = new() { Name = "Sauce" }} ] )); - - var errors = await _sut.IsValidPizza(new PizzaEntity - { - Name = "Test Pizza", - Price = 2, - Sauce = new() { Price = 1 }, - Toppings = [new () { Name = "A", Price = 2 }] - }); - errors.Should().Contain("Pizza name must be unique."); } }