ProductService tested and stable
This commit is contained in:
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user