From e07b46fcceff3eac93ee45764f21211c353e8043 Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Fri, 19 Jun 2026 23:14:10 -0400 Subject: [PATCH] add tests --- .../BreweryService.test.cs | 276 ++++++++++++++---- .../Service.Breweries.Tests.csproj | 1 + 2 files changed, 224 insertions(+), 53 deletions(-) diff --git a/web/backend/Service/Service.Breweries.Tests/BreweryService.test.cs b/web/backend/Service/Service.Breweries.Tests/BreweryService.test.cs index a6b49cb..4b371db 100644 --- a/web/backend/Service/Service.Breweries.Tests/BreweryService.test.cs +++ b/web/backend/Service/Service.Breweries.Tests/BreweryService.test.cs @@ -1,69 +1,239 @@ -using FluentAssertions; -using Xunit; -using Service.Breweries; -using API.Core.Contracts.Breweries; using Domain.Entities; +using FluentAssertions; +using Infrastructure.Repository.Breweries; +using Moq; namespace Service.Breweries.Tests; public class BreweryServiceTests { - private class FakeRepo : IBreweryRepository - { - public BreweryPost? Created; + private readonly Mock _repoMock; + private readonly BreweryService _service; - public Task GetByIdAsync(Guid id) => Task.FromResult(null); - public Task> GetAllAsync(int? limit, int? offset) => Task.FromResult>(Array.Empty()); - public Task UpdateAsync(BreweryPost brewery) { Created = brewery; return Task.CompletedTask; } - public Task DeleteAsync(Guid id) => Task.CompletedTask; - public Task CreateAsync(BreweryPost brewery) { Created = brewery; return Task.CompletedTask; } - } + public BreweryServiceTests() + { + _repoMock = new Mock(); + _service = new BreweryService(_repoMock.Object); + } - [Fact] - public async Task CreateAsync_ReturnsFailure_WhenLocationMissing() - { - var repo = new FakeRepo(); - var svc = new BreweryService(repo); + private static BreweryLocationCreateRequest ValidLocationCreateRequest() => + new( + CityId: Guid.NewGuid(), + AddressLine1: "123 Main St", + AddressLine2: null, + PostalCode: "12345", + Coordinates: null + ); - var dto = new BreweryCreateDto - { - PostedById = Guid.NewGuid(), - BreweryName = "X", - Description = "Y", - Location = null! - }; + [Fact] + public async Task GetByIdAsync_ReturnsBrewery_WhenFound() + { + var brewery = new BreweryPost { BreweryPostId = Guid.NewGuid() }; + _repoMock.Setup(r => r.GetByIdAsync(brewery.BreweryPostId)) + .ReturnsAsync(brewery); - var result = await svc.CreateAsync(dto); - result.Success.Should().BeFalse(); - result.Message.Should().Contain("Location"); - } + var result = await _service.GetByIdAsync(brewery.BreweryPostId); - [Fact] - public async Task CreateAsync_ReturnsSuccess_AndPersistsEntity() - { - var repo = new FakeRepo(); - var svc = new BreweryService(repo); + result.Should().Be(brewery); + } - var loc = new BreweryLocationCreateDto - { - CityId = Guid.NewGuid(), - AddressLine1 = "123 Main", - PostalCode = "12345" - }; + [Fact] + public async Task GetByIdAsync_ReturnsNull_WhenNotFound() + { + var id = Guid.NewGuid(); + _repoMock.Setup(r => r.GetByIdAsync(id)) + .ReturnsAsync((BreweryPost?)null); - var dto = new BreweryCreateDto - { - PostedById = Guid.NewGuid(), - BreweryName = "MyBrew", - Description = "Desc", - Location = loc - }; + var result = await _service.GetByIdAsync(id); - var result = await svc.CreateAsync(dto); + result.Should().BeNull(); + } - result.Success.Should().BeTrue(); - repo.Created.Should().NotBeNull(); - repo.Created!.BreweryName.Should().Be("MyBrew"); - result.Brewery.BreweryName.Should().Be("MyBrew"); - } + [Fact] + public async Task GetAllAsync_PassesLimitAndOffset_ToRepository() + { + _repoMock.Setup(r => r.GetAllAsync(10, 5)) + .ReturnsAsync(Array.Empty()); + + var result = await _service.GetAllAsync(10, 5); + + result.Should().BeEmpty(); + _repoMock.Verify(r => r.GetAllAsync(10, 5), Times.Once); + } + + [Fact] + public async Task GetAllAsync_ReturnsAllBreweries_FromRepository() + { + var breweries = new[] + { + new BreweryPost { BreweryPostId = Guid.NewGuid() }, + new BreweryPost { BreweryPostId = Guid.NewGuid() }, + }; + _repoMock.Setup(r => r.GetAllAsync(null, null)) + .ReturnsAsync(breweries); + + var result = await _service.GetAllAsync(); + + result.Should().BeEquivalentTo(breweries); + } + + [Fact] + public async Task CreateAsync_PersistsEntity_WithNewIdsAndCreatedAt() + { + var request = new BreweryCreateRequest( + PostedById: Guid.NewGuid(), + BreweryName: "MyBrew", + Description: "Desc", + Location: ValidLocationCreateRequest() + ); + + BreweryPost? persisted = null; + _repoMock + .Setup(r => r.CreateAsync(It.IsAny())) + .Callback(b => persisted = b) + .Returns(Task.CompletedTask); + + var before = DateTime.UtcNow; + var result = await _service.CreateAsync(request); + var after = DateTime.UtcNow; + + result.Success.Should().BeTrue(); + persisted.Should().NotBeNull(); + persisted!.BreweryPostId.Should().NotBe(Guid.Empty); + persisted.PostedById.Should().Be(request.PostedById); + persisted.BreweryName.Should().Be("MyBrew"); + persisted.Description.Should().Be("Desc"); + persisted.CreatedAt.Should().BeOnOrAfter(before).And.BeOnOrBefore(after); + persisted.UpdatedAt.Should().BeNull(); + + persisted.Location.Should().NotBeNull(); + persisted.Location!.BreweryPostLocationId.Should().NotBe(Guid.Empty); + persisted.Location.BreweryPostLocationId.Should().NotBe(persisted.BreweryPostId); + persisted.Location.CityId.Should().Be(request.Location.CityId); + persisted.Location.AddressLine1.Should().Be(request.Location.AddressLine1); + persisted.Location.PostalCode.Should().Be(request.Location.PostalCode); + + _repoMock.Verify(r => r.CreateAsync(It.IsAny()), Times.Once); + } + + [Fact] + public async Task CreateAsync_ReturnsServiceReturn_WrappingTheCreatedEntity() + { + var request = new BreweryCreateRequest( + PostedById: Guid.NewGuid(), + BreweryName: "MyBrew", + Description: "Desc", + Location: ValidLocationCreateRequest() + ); + + _repoMock + .Setup(r => r.CreateAsync(It.IsAny())) + .Returns(Task.CompletedTask); + + var result = await _service.CreateAsync(request); + + result.Success.Should().BeTrue(); + result.Brewery.BreweryName.Should().Be("MyBrew"); + result.Brewery.Location.Should().NotBeNull(); + } + + [Fact] + public async Task UpdateAsync_UpdatesNameDescription_AndSetsUpdatedAt() + { + var request = new BreweryUpdateRequest( + BreweryPostId: Guid.NewGuid(), + PostedById: Guid.NewGuid(), + BreweryName: "Renamed", + Description: "New description", + Location: null + ); + + BreweryPost? persisted = null; + _repoMock + .Setup(r => r.UpdateAsync(It.IsAny())) + .Callback(b => persisted = b) + .Returns(Task.CompletedTask); + + var before = DateTime.UtcNow; + var result = await _service.UpdateAsync(request); + var after = DateTime.UtcNow; + + result.Success.Should().BeTrue(); + persisted.Should().NotBeNull(); + persisted!.BreweryPostId.Should().Be(request.BreweryPostId); + persisted.PostedById.Should().Be(request.PostedById); + persisted.BreweryName.Should().Be("Renamed"); + persisted.Description.Should().Be("New description"); + persisted.UpdatedAt.Should().NotBeNull(); + persisted.UpdatedAt!.Value.Should().BeOnOrAfter(before).And.BeOnOrBefore(after); + } + + [Fact] + public async Task UpdateAsync_ClearsLocation_WhenRequestLocationIsNull() + { + var request = new BreweryUpdateRequest( + BreweryPostId: Guid.NewGuid(), + PostedById: Guid.NewGuid(), + BreweryName: "Name", + Description: "Description", + Location: null + ); + + BreweryPost? persisted = null; + _repoMock + .Setup(r => r.UpdateAsync(It.IsAny())) + .Callback(b => persisted = b) + .Returns(Task.CompletedTask); + + await _service.UpdateAsync(request); + + persisted!.Location.Should().BeNull(); + } + + [Fact] + public async Task UpdateAsync_SetsLocation_WhenRequestLocationProvided() + { + var locationRequest = new BreweryLocationUpdateRequest( + BreweryPostLocationId: Guid.NewGuid(), + CityId: Guid.NewGuid(), + AddressLine1: "456 Oak Ave", + AddressLine2: "Suite 2", + PostalCode: "54321", + Coordinates: null + ); + var request = new BreweryUpdateRequest( + BreweryPostId: Guid.NewGuid(), + PostedById: Guid.NewGuid(), + BreweryName: "Name", + Description: "Description", + Location: locationRequest + ); + + BreweryPost? persisted = null; + _repoMock + .Setup(r => r.UpdateAsync(It.IsAny())) + .Callback(b => persisted = b) + .Returns(Task.CompletedTask); + + await _service.UpdateAsync(request); + + persisted!.Location.Should().NotBeNull(); + persisted.Location!.BreweryPostLocationId.Should().Be(locationRequest.BreweryPostLocationId); + persisted.Location.BreweryPostId.Should().Be(request.BreweryPostId); + persisted.Location.CityId.Should().Be(locationRequest.CityId); + persisted.Location.AddressLine1.Should().Be(locationRequest.AddressLine1); + persisted.Location.AddressLine2.Should().Be(locationRequest.AddressLine2); + persisted.Location.PostalCode.Should().Be(locationRequest.PostalCode); + } + + [Fact] + public async Task DeleteAsync_DelegatesToRepository() + { + var id = Guid.NewGuid(); + _repoMock.Setup(r => r.DeleteAsync(id)).Returns(Task.CompletedTask); + + await _service.DeleteAsync(id); + + _repoMock.Verify(r => r.DeleteAsync(id), Times.Once); + } } diff --git a/web/backend/Service/Service.Breweries.Tests/Service.Breweries.Tests.csproj b/web/backend/Service/Service.Breweries.Tests/Service.Breweries.Tests.csproj index bd1c5c8..5803530 100644 --- a/web/backend/Service/Service.Breweries.Tests/Service.Breweries.Tests.csproj +++ b/web/backend/Service/Service.Breweries.Tests/Service.Breweries.Tests.csproj @@ -11,6 +11,7 @@ +