Skip to content

Commit fa065c6

Browse files
committed
Added tests for the Warehouse example's queries
1 parent d83bc9a commit fa065c6

File tree

13 files changed

+382
-45
lines changed

13 files changed

+382
-45
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Net;
4+
using System.Threading.Tasks;
5+
using Core.Testing;
6+
using FluentAssertions;
7+
using Microsoft.AspNetCore.Hosting;
8+
using Warehouse.Products.GettingProductDetails;
9+
using Warehouse.Products.GettingProducts;
10+
using Warehouse.Products.RegisteringProduct;
11+
using Xunit;
12+
13+
namespace Warehouse.Api.Tests.Products.GettingProductDetails
14+
{
15+
public class GetProductDetailsFixture: ApiFixture
16+
{
17+
protected override string ApiUrl => "/api/products";
18+
19+
protected override Func<IWebHostBuilder, IWebHostBuilder> SetupWebHostBuilder =>
20+
whb => WarehouseTestWebHostBuilder.Configure(whb, nameof(GetProductDetailsFixture));
21+
22+
public ProductDetails ExistingProduct = default!;
23+
24+
public Guid ProductId = default!;
25+
26+
public override async Task InitializeAsync()
27+
{
28+
var registerProduct = new RegisterProductRequest("IN11111", "ValidName", "ValidDescription");
29+
var registerResponse = await Post(registerProduct);
30+
31+
registerResponse.EnsureSuccessStatusCode()
32+
.StatusCode.Should().Be(HttpStatusCode.Created);
33+
34+
ProductId = await registerResponse.GetResultFromJson<Guid>();
35+
36+
var (sku, name, description) = registerProduct;
37+
ExistingProduct = new ProductDetails(ProductId, sku!, name!, description);
38+
}
39+
}
40+
41+
public class GetProductDetailsTests: IClassFixture<GetProductDetailsFixture>
42+
{
43+
private readonly GetProductDetailsFixture fixture;
44+
45+
public GetProductDetailsTests(GetProductDetailsFixture fixture)
46+
{
47+
this.fixture = fixture;
48+
}
49+
50+
[Fact]
51+
public async Task ValidRequest_With_NoParams_ShouldReturn_200()
52+
{
53+
// Given
54+
55+
// When
56+
var response = await fixture.Get(fixture.ProductId.ToString());
57+
58+
// Then
59+
response.EnsureSuccessStatusCode()
60+
.StatusCode.Should().Be(HttpStatusCode.OK);
61+
62+
var product = await response.GetResultFromJson<ProductDetails>();
63+
product.Should().NotBeNull();
64+
product.Should().BeEquivalentTo(fixture.ExistingProduct);
65+
}
66+
67+
[Theory]
68+
[InlineData(12)]
69+
[InlineData("not-a-guid")]
70+
public async Task InvalidGuidId_ShouldReturn_400(object invalidId)
71+
{
72+
// Given
73+
74+
// When
75+
var response = await fixture.Get($"{invalidId}");
76+
77+
// Then
78+
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
79+
}
80+
81+
[Fact]
82+
public async Task NotExistingId_ShouldReturn_404()
83+
{
84+
// Given
85+
var notExistingId = Guid.NewGuid();
86+
87+
// When
88+
var response = await fixture.Get($"{notExistingId}");
89+
90+
// Then
91+
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
92+
}
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Threading.Tasks;
6+
using Core.Testing;
7+
using FluentAssertions;
8+
using Microsoft.AspNetCore.Hosting;
9+
using Warehouse.Products.GettingProducts;
10+
using Warehouse.Products.RegisteringProduct;
11+
using Xunit;
12+
13+
namespace Warehouse.Api.Tests.Products.GettingProducts
14+
{
15+
public class GetProductsFixture: ApiFixture
16+
{
17+
protected override string ApiUrl => "/api/products";
18+
19+
protected override Func<IWebHostBuilder, IWebHostBuilder> SetupWebHostBuilder =>
20+
whb => WarehouseTestWebHostBuilder.Configure(whb, nameof(GetProductsFixture));
21+
22+
public IList<ProductListItem> RegisteredProducts = new List<ProductListItem>();
23+
24+
public override async Task InitializeAsync()
25+
{
26+
var productsToRegister = new[]
27+
{
28+
new RegisterProductRequest("ZX1234", "ValidName", "ValidDescription"),
29+
new RegisterProductRequest("AD5678", "OtherValidName", "OtherValidDescription"),
30+
new RegisterProductRequest("BH90210", "AnotherValid", "AnotherValidDescription")
31+
};
32+
33+
foreach (var registerProduct in productsToRegister)
34+
{
35+
var registerResponse = await Post(registerProduct);
36+
registerResponse.EnsureSuccessStatusCode()
37+
.StatusCode.Should().Be(HttpStatusCode.Created);
38+
39+
var createdId = await registerResponse.GetResultFromJson<Guid>();
40+
41+
var (sku, name, _) = registerProduct;
42+
RegisteredProducts.Add(new ProductListItem(createdId, sku!, name!));
43+
}
44+
}
45+
}
46+
47+
public class GetProductsTests: IClassFixture<GetProductsFixture>
48+
{
49+
private readonly GetProductsFixture fixture;
50+
51+
public GetProductsTests(GetProductsFixture fixture)
52+
{
53+
this.fixture = fixture;
54+
}
55+
56+
[Fact]
57+
public async Task ValidRequest_With_NoParams_ShouldReturn_200()
58+
{
59+
// Given
60+
61+
// When
62+
var response = await fixture.Get();
63+
64+
// Then
65+
response.EnsureSuccessStatusCode()
66+
.StatusCode.Should().Be(HttpStatusCode.OK);
67+
68+
var products = await response.GetResultFromJson<IReadOnlyList<ProductListItem>>();
69+
products.Should().NotBeEmpty();
70+
products.Should().BeEquivalentTo(fixture.RegisteredProducts);
71+
}
72+
73+
[Fact]
74+
public async Task ValidRequest_With_Filter_ShouldReturn_SubsetOfRecords()
75+
{
76+
// Given
77+
var filteredRecord = fixture.RegisteredProducts.First();
78+
var filter = fixture.RegisteredProducts.First().Sku.Substring(1);
79+
80+
// When
81+
var response = await fixture.Get($"?filter={filter}");
82+
83+
// Then
84+
response.EnsureSuccessStatusCode()
85+
.StatusCode.Should().Be(HttpStatusCode.OK);
86+
87+
var products = await response.GetResultFromJson<IReadOnlyList<ProductListItem>>();
88+
products.Should().NotBeEmpty();
89+
products.Should().BeEquivalentTo(new List<ProductListItem>{filteredRecord});
90+
}
91+
92+
93+
94+
[Fact]
95+
public async Task ValidRequest_With_Paging_ShouldReturn_PageOfRecords()
96+
{
97+
// Given
98+
const int page = 2;
99+
const int pageSize = 1;
100+
var filteredRecords = fixture.RegisteredProducts
101+
.Skip(page - 1)
102+
.Take(pageSize)
103+
.ToList();
104+
105+
// When
106+
var response = await fixture.Get($"?page={page}&pageSize={pageSize}");
107+
108+
// Then
109+
response.EnsureSuccessStatusCode()
110+
.StatusCode.Should().Be(HttpStatusCode.OK);
111+
112+
var products = await response.GetResultFromJson<IReadOnlyList<ProductListItem>>();
113+
products.Should().NotBeEmpty();
114+
products.Should().BeEquivalentTo(filteredRecords);
115+
}
116+
117+
[Fact]
118+
public async Task NegativePage_ShouldReturn_400()
119+
{
120+
// Given
121+
var pageSize = -20;
122+
123+
// When
124+
var response = await fixture.Get($"?page={pageSize}");
125+
126+
// Then
127+
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
128+
}
129+
130+
[Theory]
131+
[InlineData(0)]
132+
[InlineData(-20)]
133+
public async Task NegativeOrZeroPageSize_ShouldReturn_400(int pageSize)
134+
{
135+
// Given
136+
137+
// When
138+
var response = await fixture.Get($"?page={pageSize}");
139+
140+
// Then
141+
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
142+
}
143+
}
144+
}

Sample/Warehouse/Warehouse.Api.Tests/Products/RegisteringProduct/RegisterProductTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
namespace Warehouse.Api.Tests.Products.RegisteringProduct
1111
{
12-
public class RegisteringProduct
12+
public class RegisteringProductTests
1313
{
1414
public class RegisterProductFixture: ApiFixture
1515
{
1616
protected override string ApiUrl => "/api/products";
1717

1818
protected override Func<IWebHostBuilder, IWebHostBuilder> SetupWebHostBuilder =>
19-
WarehouseTestWebHostBuilder.Configure;
19+
whb => WarehouseTestWebHostBuilder.Configure(whb, nameof(RegisterProductFixture));
2020
}
2121

2222
public class RegisterProductTests: IClassFixture<RegisterProductFixture>
@@ -78,7 +78,7 @@ public async Task RequestForExistingSKUShouldFail_ShouldReturn_409()
7878
private static string ValidSKU => $"CC{DateTime.Now.Ticks}";
7979
private const string ValidDescription = "VALID_DESCRIPTION";
8080

81-
public static TheoryData<RegisterProductRequest> ValidRequests = new ()
81+
public static TheoryData<RegisterProductRequest> ValidRequests = new()
8282
{
8383
new RegisterProductRequest(ValidSKU, ValidName, ValidDescription),
8484
new RegisterProductRequest(ValidSKU, ValidName, null)

Sample/Warehouse/Warehouse.Api.Tests/Warehouse.Api.Tests.csproj

-5
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@
3232
<ProjectReference Include="..\Warehouse\Warehouse.csproj" />
3333
</ItemGroup>
3434

35-
<ItemGroup>
36-
<Folder Include="Products\GettingProductDetails" />
37-
<Folder Include="Products\GettingProducts" />
38-
</ItemGroup>
39-
4035
<ItemGroup>
4136
<Content Include="appsettings.Development.json">
4237
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>

Sample/Warehouse/Warehouse.Api.Tests/WarehouseTestWebHostBuilder.cs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
1-
using Core.WebApi.Middlewares.ExceptionHandling;
1+
using Castle.Core.Configuration;
2+
using Core.WebApi.Middlewares.ExceptionHandling;
23
using Microsoft.AspNetCore.Builder;
34
using Microsoft.AspNetCore.Hosting;
45
using Microsoft.EntityFrameworkCore;
6+
using Microsoft.Extensions.Configuration;
57
using Microsoft.Extensions.DependencyInjection;
68
using Warehouse.Storage;
9+
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;
710

811
namespace Warehouse.Api.Tests
912
{
1013
public static class WarehouseTestWebHostBuilder
1114
{
12-
public static IWebHostBuilder Configure(IWebHostBuilder webHostBuilder)
15+
public static IWebHostBuilder Configure(IWebHostBuilder webHostBuilder, string schemaName)
1316
{
1417
webHostBuilder
1518
.ConfigureServices(services =>
1619
{
1720
services.AddRouting()
1821
.AddAuthorization()
1922
.AddCors()
20-
.AddWarehouseServices();
23+
.AddWarehouseServices()
24+
.AddTransient<DbContextOptions<WarehouseDBContext>>(s =>
25+
{
26+
var connectionString = s.GetRequiredService<IConfiguration>().GetConnectionString("WarehouseDB");
27+
var options = new DbContextOptionsBuilder<WarehouseDBContext>();
28+
options.UseNpgsql(
29+
$"{connectionString}; searchpath = {schemaName.ToLower()}",
30+
x => x.MigrationsHistoryTable("__EFMigrationsHistory", schemaName.ToLower()));
31+
return options.Options;
32+
});
2133
})
2234
.Configure(app =>
2335
{

0 commit comments

Comments
 (0)