ProductService tested and stable

This commit is contained in:
Khwezi Mngoma
2026-05-28 17:28:33 +02:00
parent 2a0b34c730
commit 4e53ff8a37
3 changed files with 68 additions and 10 deletions
@@ -39,6 +39,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Using Include="System.Text.Json" />
<Using Include="System.Diagnostics" /> <Using Include="System.Diagnostics" />
<Using Include="Xunit" /> <Using Include="Xunit" />
</ItemGroup> </ItemGroup>
@@ -1,7 +1,6 @@
using LiteCharms.Features.MidrandBooks.Products; using LiteCharms.Features.MidrandBooks.Products;
using LiteCharms.Features.MidrandBooks.Products.Models; using LiteCharms.Features.MidrandBooks.Products.Models;
using LiteCharms.Features.Models; using LiteCharms.Features.Models;
using System.Text.Json;
namespace LiteCharms.Features.MidrandBooks.Tests; namespace LiteCharms.Features.MidrandBooks.Tests;
@@ -9,6 +8,59 @@ public class ProductServiceFeatureTest(Fixture fixture, ITestOutputHelper output
{ {
private readonly ProductService productService = fixture.Services.GetRequiredService<ProductService>(); private readonly ProductService productService = fixture.Services.GetRequiredService<ProductService>();
[IntegrationFact]
public async Task GetProductPriceAsync_ShouldReturn_RetultOneProductPrice()
{
var result = await productService.GetProductPriceAsync(2, fixture.CancellationToken);
Assert.True(result.IsSuccess);
Assert.NotNull(result.Value);
output.WriteLine(JsonSerializer.Serialize(result.Value));
}
[IntegrationFact]
public async Task GetProductPricesAsync_ShouldReturn_RetultProductPriceList()
{
var result = await productService.GetProductPricesAsync(2, fixture.CancellationToken);
Assert.True(result.IsSuccess);
Assert.NotEmpty(result.Value);
output.WriteLine(JsonSerializer.Serialize(result.Value));
}
[IntegrationFact]
public async Task SearchProductsAsync_ShouldReturn_RetultMatchingProducts()
{
var filter = new ProductFilter
{
Name = "system",
Manufacturer = "techwave",
SerialNumber = "2024",
MinPrice = 10,
MaxPrice = 30
};
var result = await productService.SearchProductsAsync(filter, fixture.CancellationToken);
Assert.True(result.IsSuccess);
Assert.NotEmpty(result.Value);
output.WriteLine(JsonSerializer.Serialize(result.Value));
}
[IntegrationFact]
public async Task GetProductAsync_ShouldReturn_RetultOneProduct()
{
var result = await productService.GetProductAsync(2, fixture.CancellationToken);
Assert.True(result.IsSuccess);
Assert.NotNull(result.Value);
output.WriteLine(JsonSerializer.Serialize(result.Value));
}
[IntegrationFact] [IntegrationFact]
public async Task GetProductsAsync_ShouldReturn_RetultProducts() public async Task GetProductsAsync_ShouldReturn_RetultProducts()
{ {
@@ -64,17 +64,22 @@ public sealed class ProductService(IDbContextFactory<MidrandBooksDbContext> cont
var query = context.Products.AsQueryable(); var query = context.Products.AsQueryable();
var cultureInfo = CultureInfo.InvariantCulture;
if (!string.IsNullOrWhiteSpace(filter.Name))
query = query.Where(p => EF.Functions.ILike(p.Name!, $"%{filter.Name}%"));
if (!string.IsNullOrWhiteSpace(filter.Title)) if (!string.IsNullOrWhiteSpace(filter.Title))
query = query.Where(p => p.Name!.Contains(filter.Title)); query = query.Where(p => EF.Functions.ILike(p.Name!, $"%{filter.Title}%"));
if (!string.IsNullOrWhiteSpace(filter.Category)) if (!string.IsNullOrWhiteSpace(filter.Category))
query = query.Where(p => p.Categories!.Any(c => c == filter.Category)); query = query.Where(p => p.Categories.Contains(filter.Category));
if (!string.IsNullOrWhiteSpace(filter.Manufacturer)) if (!string.IsNullOrWhiteSpace(filter.Manufacturer))
query = query.Where(p => p.Metadata!.Manufacturer == filter.Manufacturer); query = query.Where(p => EF.Functions.ILike(p.Metadata!.Manufacturer!, $"%{filter.Manufacturer}%"));
if (!string.IsNullOrWhiteSpace(filter.SerialNumber)) if (!string.IsNullOrWhiteSpace(filter.SerialNumber))
query = query.Where(p => p.Metadata!.SerialNumber == filter.SerialNumber); query = query.Where(p => EF.Functions.ILike(p.Metadata!.SerialNumber!, $"%{filter.SerialNumber}%"));
if (filter.MinPrice > 0) if (filter.MinPrice > 0)
query = query.Where(p => p.Prices!.Any(pr => pr.Amount >= filter.MinPrice && pr.Amount <= filter.MaxPrice)); query = query.Where(p => p.Prices!.Any(pr => pr.Amount >= filter.MinPrice && pr.Amount <= filter.MaxPrice));
@@ -165,7 +170,7 @@ public sealed class ProductService(IDbContextFactory<MidrandBooksDbContext> cont
} }
} }
public async ValueTask<Result<ProductPrice[]>> GetProductPriceAsync(long productId, CancellationToken cancellationToken = default) public async ValueTask<Result<ProductPrice>> GetProductPriceAsync(long productId, CancellationToken cancellationToken = default)
{ {
try try
{ {
@@ -175,16 +180,16 @@ public sealed class ProductService(IDbContextFactory<MidrandBooksDbContext> cont
.AsNoTracking() .AsNoTracking()
.OrderByDescending(p => p.CreatedAt) .OrderByDescending(p => p.CreatedAt)
.ThenBy(p => p.UpdatedAt) .ThenBy(p => p.UpdatedAt)
.FirstOrDefaultAsync(p => p.ProductId == productId, cancellationToken); .FirstOrDefaultAsync(p => p.ProductId == productId && p.Enabled, cancellationToken);
return product is not null return product is not null
? Result.Ok(new[] { product.ToModel() }) ? Result.Ok(product.ToModel())
: Result.Fail<ProductPrice[]>(new Error($"No price found for product with ID {productId}")); : Result.Fail<ProductPrice>(new Error($"No price found for product with ID {productId}"));
} }
catch (Exception ex) catch (Exception ex)
{ {
return Result.Fail<ProductPrice[]>(new Error(ex.Message).CausedBy(ex)); return Result.Fail<ProductPrice>(new Error(ex.Message).CausedBy(ex));
} }
} }