Add initial implementation of product management API
This commit is contained in:
21
EndavaTask.Tests/EndavaTask.Tests.csproj
Normal file
21
EndavaTask.Tests/EndavaTask.Tests.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EndavaTask\EndavaTask.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
85
EndavaTask.Tests/EntityDtoMappingsTests.cs
Normal file
85
EndavaTask.Tests/EntityDtoMappingsTests.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using EndavaTask.Contracts;
|
||||
using EndavaTask.Dtos;
|
||||
using EndavaTask.Mappings;
|
||||
using EndavaTask.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace EndavaTask.Tests;
|
||||
|
||||
public class EntityDtoMappingsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Product_ToDto_And_ToEntity_Roundtrip_Works()
|
||||
{
|
||||
var entity = new Product
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Keyboard",
|
||||
Price = 90m,
|
||||
CategoryId = Guid.NewGuid()
|
||||
};
|
||||
|
||||
var dto = entity.ToDto();
|
||||
var mappedBack = dto.ToEntity();
|
||||
|
||||
Assert.Equal(entity.Id, dto.Id);
|
||||
Assert.Equal(entity.Name, dto.Name);
|
||||
Assert.Equal(entity.Price, dto.Price);
|
||||
Assert.Equal(entity.CategoryId, dto.CategoryId);
|
||||
|
||||
Assert.Equal(entity.Id, mappedBack.Id);
|
||||
Assert.Equal(entity.Name, mappedBack.Name);
|
||||
Assert.Equal(entity.Price, mappedBack.Price);
|
||||
Assert.Equal(entity.CategoryId, mappedBack.CategoryId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Category_ToDto_And_ToEntity_Roundtrip_Works()
|
||||
{
|
||||
var entity = new Category
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Home",
|
||||
Description = "Home essentials"
|
||||
};
|
||||
|
||||
var dto = entity.ToDto();
|
||||
var mappedBack = dto.ToEntity();
|
||||
|
||||
Assert.Equal(entity.Id, dto.Id);
|
||||
Assert.Equal(entity.Name, dto.Name);
|
||||
Assert.Equal(entity.Description, dto.Description);
|
||||
|
||||
Assert.Equal(entity.Id, mappedBack.Id);
|
||||
Assert.Equal(entity.Name, mappedBack.Name);
|
||||
Assert.Equal(entity.Description, mappedBack.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PagedProducts_ToDto_MapsMetadataAndItems()
|
||||
{
|
||||
var paged = new PagedResult<Product>
|
||||
{
|
||||
Items =
|
||||
[
|
||||
new Product { Id = Guid.NewGuid(), Name = "Laptop", Price = 1200m, CategoryId = Guid.NewGuid() },
|
||||
new Product { Id = Guid.NewGuid(), Name = "Monitor", Price = 300m, CategoryId = Guid.NewGuid() }
|
||||
],
|
||||
PageNumber = 2,
|
||||
PageSize = 2,
|
||||
TotalCount = 5,
|
||||
TotalPages = 3
|
||||
};
|
||||
|
||||
var dtoPaged = paged.ToDto();
|
||||
|
||||
Assert.Equal(2, dtoPaged.Items.Count);
|
||||
Assert.Equal(2, dtoPaged.PageNumber);
|
||||
Assert.Equal(2, dtoPaged.PageSize);
|
||||
Assert.Equal(5, dtoPaged.TotalCount);
|
||||
Assert.Equal(3, dtoPaged.TotalPages);
|
||||
|
||||
var first = Assert.IsType<ProductDto>(dtoPaged.Items.First());
|
||||
Assert.Equal("Laptop", first.Name);
|
||||
}
|
||||
}
|
||||
44
EndavaTask.Tests/InMemoryProductRepositoryTests.cs
Normal file
44
EndavaTask.Tests/InMemoryProductRepositoryTests.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using EndavaTask.Contracts;
|
||||
using EndavaTask.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace EndavaTask.Tests;
|
||||
|
||||
public class InMemoryProductRepositoryTests
|
||||
{
|
||||
private readonly InMemoryProductRepository _repository = new();
|
||||
|
||||
[Fact]
|
||||
public void GetFilteredProducts_FiltersByNameCategoryAndPriceRange_WithPagination()
|
||||
{
|
||||
var filter = new ProductFilterQuery
|
||||
{
|
||||
Name = "mon",
|
||||
CategoryId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
|
||||
MinPrice = 200m,
|
||||
MaxPrice = 350m
|
||||
};
|
||||
|
||||
var result = _repository.GetFilteredProducts(filter, new PaginationQuery { PageNumber = 1, PageSize = 10 });
|
||||
|
||||
Assert.Single(result.Items);
|
||||
|
||||
var product = Assert.Single(result.Items);
|
||||
|
||||
Assert.Equal("Monitor", product.Name);
|
||||
Assert.Equal(1, result.TotalCount);
|
||||
Assert.Equal(1, result.TotalPages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFilteredProducts_ReturnsPagedData_WhenNoFilters()
|
||||
{
|
||||
var result = _repository.GetFilteredProducts(new ProductFilterQuery(), new PaginationQuery { PageNumber = 2, PageSize = 2 });
|
||||
|
||||
Assert.Equal(2, result.Items.Count);
|
||||
Assert.Equal(5, result.TotalCount);
|
||||
Assert.Equal(3, result.TotalPages);
|
||||
Assert.Equal(2, result.PageNumber);
|
||||
Assert.Equal(2, result.PageSize);
|
||||
}
|
||||
}
|
||||
90
EndavaTask.Tests/ProductServiceTests.cs
Normal file
90
EndavaTask.Tests/ProductServiceTests.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using EndavaTask.Contracts;
|
||||
using EndavaTask.Data;
|
||||
using EndavaTask.Dtos;
|
||||
using EndavaTask.Exceptions;
|
||||
using EndavaTask.Models;
|
||||
using EndavaTask.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace EndavaTask.Tests;
|
||||
|
||||
public class ProductServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetProducts_WithRepositoryResult_MapsAndReturnsPagedResult()
|
||||
{
|
||||
var categoryId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
|
||||
var repositoryMock = new Mock<IProductRepository>();
|
||||
|
||||
repositoryMock
|
||||
.Setup(r => r.CategoryExists(categoryId))
|
||||
.Returns(true);
|
||||
|
||||
repositoryMock
|
||||
.Setup(r => r.GetFilteredProducts(It.IsAny<ProductFilterQuery>(), It.IsAny<PaginationQuery>()))
|
||||
.Returns(new PagedResult<Product>
|
||||
{
|
||||
Items =
|
||||
[
|
||||
new Product { Id = Guid.NewGuid(), Name = "Laptop", Price = 1200m, CategoryId = categoryId },
|
||||
new Product { Id = Guid.NewGuid(), Name = "Headphones", Price = 180m, CategoryId = categoryId }
|
||||
],
|
||||
PageNumber = 1,
|
||||
PageSize = 2,
|
||||
TotalCount = 3,
|
||||
TotalPages = 2
|
||||
});
|
||||
|
||||
var service = new ProductService(repositoryMock.Object);
|
||||
var result = service.GetProducts(new ProductFilterQuery { CategoryId = categoryId }, new PaginationQuery { PageNumber = 1, PageSize = 2 });
|
||||
var value = Assert.IsType<PagedResult<ProductDto>>(result);
|
||||
|
||||
Assert.Equal(2, value.Items.Count);
|
||||
Assert.Equal(3, value.TotalCount);
|
||||
Assert.Equal(2, value.TotalPages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateProduct_WithRepositoryEntity_ReturnsMappedDto()
|
||||
{
|
||||
var productId = Guid.Parse("55555555-5555-5555-5555-555555555555");
|
||||
var categoryId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
|
||||
|
||||
var repositoryMock = new Mock<IProductRepository>();
|
||||
|
||||
repositoryMock
|
||||
.Setup(r => r.UpdateProduct(productId, It.IsAny<UpdateProductRequest>()))
|
||||
.Returns(new Product
|
||||
{
|
||||
Id = productId,
|
||||
Name = "Updated Monitor",
|
||||
Price = 350m,
|
||||
CategoryId = categoryId
|
||||
});
|
||||
|
||||
var service = new ProductService(repositoryMock.Object);
|
||||
var result = service.UpdateProduct(productId, new UpdateProductRequest { Name = "Updated Monitor", Price = 350m });
|
||||
var value = Assert.IsType<ProductDto>(result);
|
||||
|
||||
Assert.Equal("Updated Monitor", value.Name);
|
||||
Assert.Equal(350m, value.Price);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProducts_WithUnknownCategory_ThrowsValidationException()
|
||||
{
|
||||
var repositoryMock = new Mock<IProductRepository>();
|
||||
|
||||
repositoryMock
|
||||
.Setup(r => r.CategoryExists(It.IsAny<Guid>()))
|
||||
.Returns(false);
|
||||
|
||||
var service = new ProductService(repositoryMock.Object);
|
||||
|
||||
var exception = Assert.Throws<ApiValidationException>(() =>
|
||||
service.GetProducts(new ProductFilterQuery { CategoryId = Guid.NewGuid() }, new PaginationQuery()));
|
||||
|
||||
Assert.True(exception.Errors.ContainsKey(nameof(ProductFilterQuery.CategoryId)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user