mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 17:47:22 +00:00
add tests
This commit is contained in:
@@ -1,69 +1,239 @@
|
|||||||
using FluentAssertions;
|
|
||||||
using Xunit;
|
|
||||||
using Service.Breweries;
|
|
||||||
using API.Core.Contracts.Breweries;
|
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Infrastructure.Repository.Breweries;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
namespace Service.Breweries.Tests;
|
namespace Service.Breweries.Tests;
|
||||||
|
|
||||||
public class BreweryServiceTests
|
public class BreweryServiceTests
|
||||||
{
|
{
|
||||||
private class FakeRepo : IBreweryRepository
|
private readonly Mock<IBreweryRepository> _repoMock;
|
||||||
{
|
private readonly BreweryService _service;
|
||||||
public BreweryPost? Created;
|
|
||||||
|
|
||||||
public Task<BreweryPost?> GetByIdAsync(Guid id) => Task.FromResult<BreweryPost?>(null);
|
public BreweryServiceTests()
|
||||||
public Task<IEnumerable<BreweryPost>> GetAllAsync(int? limit, int? offset) => Task.FromResult<IEnumerable<BreweryPost>>(Array.Empty<BreweryPost>());
|
{
|
||||||
public Task UpdateAsync(BreweryPost brewery) { Created = brewery; return Task.CompletedTask; }
|
_repoMock = new Mock<IBreweryRepository>();
|
||||||
public Task DeleteAsync(Guid id) => Task.CompletedTask;
|
_service = new BreweryService(_repoMock.Object);
|
||||||
public Task CreateAsync(BreweryPost brewery) { Created = brewery; return Task.CompletedTask; }
|
}
|
||||||
|
|
||||||
|
private static BreweryLocationCreateRequest ValidLocationCreateRequest() =>
|
||||||
|
new(
|
||||||
|
CityId: Guid.NewGuid(),
|
||||||
|
AddressLine1: "123 Main St",
|
||||||
|
AddressLine2: null,
|
||||||
|
PostalCode: "12345",
|
||||||
|
Coordinates: 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 _service.GetByIdAsync(brewery.BreweryPostId);
|
||||||
|
|
||||||
|
result.Should().Be(brewery);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateAsync_ReturnsFailure_WhenLocationMissing()
|
public async Task GetByIdAsync_ReturnsNull_WhenNotFound()
|
||||||
{
|
{
|
||||||
var repo = new FakeRepo();
|
var id = Guid.NewGuid();
|
||||||
var svc = new BreweryService(repo);
|
_repoMock.Setup(r => r.GetByIdAsync(id))
|
||||||
|
.ReturnsAsync((BreweryPost?)null);
|
||||||
|
|
||||||
var dto = new BreweryCreateDto
|
var result = await _service.GetByIdAsync(id);
|
||||||
{
|
|
||||||
PostedById = Guid.NewGuid(),
|
|
||||||
BreweryName = "X",
|
|
||||||
Description = "Y",
|
|
||||||
Location = null!
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await svc.CreateAsync(dto);
|
result.Should().BeNull();
|
||||||
result.Success.Should().BeFalse();
|
|
||||||
result.Message.Should().Contain("Location");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateAsync_ReturnsSuccess_AndPersistsEntity()
|
public async Task GetAllAsync_PassesLimitAndOffset_ToRepository()
|
||||||
{
|
{
|
||||||
var repo = new FakeRepo();
|
_repoMock.Setup(r => r.GetAllAsync(10, 5))
|
||||||
var svc = new BreweryService(repo);
|
.ReturnsAsync(Array.Empty<BreweryPost>());
|
||||||
|
|
||||||
var loc = new BreweryLocationCreateDto
|
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()
|
||||||
{
|
{
|
||||||
CityId = Guid.NewGuid(),
|
var breweries = new[]
|
||||||
AddressLine1 = "123 Main",
|
{
|
||||||
PostalCode = "12345"
|
new BreweryPost { BreweryPostId = Guid.NewGuid() },
|
||||||
|
new BreweryPost { BreweryPostId = Guid.NewGuid() },
|
||||||
};
|
};
|
||||||
|
_repoMock.Setup(r => r.GetAllAsync(null, null))
|
||||||
|
.ReturnsAsync(breweries);
|
||||||
|
|
||||||
var dto = new BreweryCreateDto
|
var result = await _service.GetAllAsync();
|
||||||
|
|
||||||
|
result.Should().BeEquivalentTo(breweries);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateAsync_PersistsEntity_WithNewIdsAndCreatedAt()
|
||||||
{
|
{
|
||||||
PostedById = Guid.NewGuid(),
|
var request = new BreweryCreateRequest(
|
||||||
BreweryName = "MyBrew",
|
PostedById: Guid.NewGuid(),
|
||||||
Description = "Desc",
|
BreweryName: "MyBrew",
|
||||||
Location = loc
|
Description: "Desc",
|
||||||
};
|
Location: ValidLocationCreateRequest()
|
||||||
|
);
|
||||||
|
|
||||||
var result = await svc.CreateAsync(dto);
|
BreweryPost? persisted = null;
|
||||||
|
_repoMock
|
||||||
|
.Setup(r => r.CreateAsync(It.IsAny<BreweryPost>()))
|
||||||
|
.Callback<BreweryPost>(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<BreweryPost>()), 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<BreweryPost>()))
|
||||||
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
var result = await _service.CreateAsync(request);
|
||||||
|
|
||||||
result.Success.Should().BeTrue();
|
result.Success.Should().BeTrue();
|
||||||
repo.Created.Should().NotBeNull();
|
|
||||||
repo.Created!.BreweryName.Should().Be("MyBrew");
|
|
||||||
result.Brewery.BreweryName.Should().Be("MyBrew");
|
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<BreweryPost>()))
|
||||||
|
.Callback<BreweryPost>(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<BreweryPost>()))
|
||||||
|
.Callback<BreweryPost>(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<BreweryPost>()))
|
||||||
|
.Callback<BreweryPost>(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.9.2" />
|
<PackageReference Include="xunit" Version="2.9.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||||
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.9.0" />
|
<PackageReference Include="FluentAssertions" Version="6.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user