零度框架 1.0 版本正式发布,共 184 项改进。
This commit is contained in:
1 parent
c14a872b77
commit
baf06cd88f
182 files changed
+2537
-1613
No files matched your search
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using Microsoft.AspNetCore.Authentication.BearerToken;
|
||||
using System.Dynamic;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace HelloShop.FunctionalTests
|
||||
{
|
||||
public class FirstWebApiIntegrationTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task WebAppRootReturnsOkStatusCode()
|
||||
{
|
||||
// Arrange
|
||||
IDistributedApplicationTestingBuilder appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.HelloShop_AppHost>();
|
||||
await using DistributedApplication app = await appHost.BuildAsync();
|
||||
await app.StartAsync();
|
||||
|
||||
// Act
|
||||
HttpClient httpClient = app.CreateHttpClient("webapp");
|
||||
HttpResponseMessage response = await httpClient.GetAsync("/");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IdetityServiceAccountLoginReturnsSuccessStatusCode()
|
||||
{
|
||||
// Arrange
|
||||
IDistributedApplicationTestingBuilder appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.HelloShop_AppHost>();
|
||||
await using DistributedApplication app = await appHost.BuildAsync();
|
||||
await app.StartAsync();
|
||||
|
||||
// Act
|
||||
HttpClient httpClient = app.CreateHttpClient("identityservice");
|
||||
HttpResponseMessage response = await httpClient.PostAsJsonAsync("api/Account/Login", new
|
||||
{
|
||||
UserName = "guest",
|
||||
Password = "guest"
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IdetityServiceAccountLoginReturnsAccessToken()
|
||||
{
|
||||
// Arrange
|
||||
IDistributedApplicationTestingBuilder appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.HelloShop_AppHost>();
|
||||
await using DistributedApplication app = await appHost.BuildAsync();
|
||||
await app.StartAsync();
|
||||
|
||||
// Act
|
||||
HttpClient httpClient = app.CreateHttpClient("identityservice");
|
||||
HttpResponseMessage response = await httpClient.PostAsJsonAsync("api/Account/Login", new
|
||||
{
|
||||
UserName = "guest",
|
||||
Password = "guest"
|
||||
});
|
||||
dynamic? result = await response.Content.ReadFromJsonAsync<ExpandoObject>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result?.accessToken);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IdetityServiceAccountLoginReturnsTokenExpiresInSeconds()
|
||||
{
|
||||
// Arrange
|
||||
IDistributedApplicationTestingBuilder appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.HelloShop_AppHost>();
|
||||
await using DistributedApplication app = await appHost.BuildAsync();
|
||||
|
||||
await app.StartAsync();
|
||||
|
||||
// Act
|
||||
HttpClient httpClient = app.CreateHttpClient("identityservice");
|
||||
HttpResponseMessage response = await httpClient.PostAsJsonAsync("api/Account/Login", new
|
||||
{
|
||||
UserName = "guest",
|
||||
Password = "guest"
|
||||
});
|
||||
JsonNode? result = await response.Content.ReadFromJsonAsync<JsonNode>();
|
||||
int expiresInSeconds = result?["expiresIn"]?.GetValue<int>() ?? default;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3600, expiresInSeconds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProductServiceGetProductReturnsProductDetails()
|
||||
{
|
||||
// Arrange
|
||||
IDistributedApplicationTestingBuilder appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.HelloShop_AppHost>();
|
||||
|
||||
await using DistributedApplication app = await appHost.BuildAsync();
|
||||
await app.StartAsync();
|
||||
|
||||
// Act
|
||||
HttpClient identityServiceHttpClient = app.CreateHttpClient("identityservice");
|
||||
HttpResponseMessage loginResponse = await identityServiceHttpClient.PostAsJsonAsync("api/Account/Login", new
|
||||
{
|
||||
UserName = "admin",
|
||||
Password = "admin"
|
||||
});
|
||||
|
||||
AccessTokenResponse? accessTokenResponse = await loginResponse.Content.ReadFromJsonAsync<AccessTokenResponse>();
|
||||
|
||||
HttpClient productServiceHttpClient = app.CreateHttpClient("productservice");
|
||||
productServiceHttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessTokenResponse?.AccessToken);
|
||||
|
||||
HttpResponseMessage productDetailsResponse = await productServiceHttpClient.GetAsync("api/Products/1");
|
||||
|
||||
JsonNode? result = await productDetailsResponse.Content.ReadFromJsonAsync<JsonNode>();
|
||||
|
||||
string? productName = result?["Name"]?.GetValue<string>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(productName);
|
||||
Assert.Equal("Product 1", productName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.Testing" Version="8.0.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="xunit" Version="2.5.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\HelloShop.AppHost\HelloShop.AppHost.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Aspire.Hosting.Testing" />
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ProductService.FunctionalTests.Utilities;
|
||||
using HelloShop.ProductService.Models.Products;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace HelloShop.ProductService.FunctionalTests
|
||||
{
|
||||
public class BrandApiIntegrationTest(CustomWebApplicationFactory<Program> factory) : IClassFixture<CustomWebApplicationFactory<Program>>
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetBrandByIdReturnsUnauthorizedStatusCode()
|
||||
{
|
||||
// Arrange
|
||||
HttpClient client = factory.CreateClient();
|
||||
|
||||
// Act
|
||||
HttpResponseMessage response = await client.GetAsync("api/Brands/1");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetBrandByIdReturnsBrandDetailsResponse()
|
||||
{
|
||||
// Arrange
|
||||
HttpClient client = factory.CreateClient();
|
||||
|
||||
// Act
|
||||
HttpResponseMessage response = await client.GetAsync("api/Brands/1");
|
||||
BrandDetailsResponse? brandDetails = await response.Content.ReadFromJsonAsync<BrandDetailsResponse>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(brandDetails);
|
||||
Assert.Equal(1, brandDetails.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
global using Xunit;
|
||||
+34
-20
@@ -1,21 +1,35 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0-release-24177-07" />
|
||||
<PackageReference Include="xunit" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\HelloShop.ProductService\HelloShop.ProductService.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace HelloShop.ProductService.FunctionalTests
|
||||
{
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ProductService.EntityFrameworks;
|
||||
using HelloShop.ServiceDefaults.Authorization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.Data.Common;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace HelloShop.ProductService.FunctionalTests.Utilities
|
||||
{
|
||||
public class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class
|
||||
{
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
ServiceDescriptor? dbContextDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ProductServiceDbContext>));
|
||||
|
||||
if (dbContextDescriptor != null)
|
||||
{
|
||||
services.Remove(dbContextDescriptor);
|
||||
}
|
||||
|
||||
// Create open SqliteConnection so EF won't automatically close it.
|
||||
services.AddSingleton(container =>
|
||||
{
|
||||
DbConnection connection = new SqliteConnection("DataSource=:memory:");
|
||||
connection.Open();
|
||||
|
||||
return connection;
|
||||
});
|
||||
|
||||
services.AddDbContext<ProductServiceDbContext>((container, options) =>
|
||||
{
|
||||
var connection = container.GetRequiredService<DbConnection>();
|
||||
options.UseSqlite(connection);
|
||||
});
|
||||
|
||||
services.Replace(ServiceDescriptor.Transient<IPermissionChecker, FakePermissionChecker>());
|
||||
});
|
||||
|
||||
builder.UseEnvironment(Environments.Development);
|
||||
}
|
||||
|
||||
protected override void ConfigureClient(HttpClient client)
|
||||
{
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", FakeAccessTokenCreator.Create());
|
||||
|
||||
base.ConfigureClient(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ServiceDefaults.Constants;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace HelloShop.ProductService.FunctionalTests.Utilities
|
||||
{
|
||||
public class FakeAccessTokenCreator
|
||||
{
|
||||
public static string Create()
|
||||
{
|
||||
DateTimeOffset utcNow = TimeProvider.System.GetUtcNow();
|
||||
|
||||
SymmetricSecurityKey signingKey = new(Encoding.Default.GetBytes(IdentityConstants.IssuerSigningKey));
|
||||
|
||||
var claimsIdentity = new ClaimsIdentity([new Claim(ClaimTypes.NameIdentifier, "1"), new Claim(ClaimTypes.Name, "admin"), new Claim(CustomClaimTypes.RoleIdentifier, "1")]);
|
||||
|
||||
SecurityTokenDescriptor accessTokenDescriptor = new()
|
||||
{
|
||||
Subject = claimsIdentity,
|
||||
SigningCredentials = new(signingKey, SecurityAlgorithms.HmacSha256),
|
||||
Expires = utcNow.Add(TimeSpan.FromDays(byte.MaxValue)).LocalDateTime,
|
||||
};
|
||||
|
||||
JwtSecurityTokenHandler tokenHandler = new();
|
||||
|
||||
JwtSecurityToken jwtSecurityToken = tokenHandler.CreateJwtSecurityToken(accessTokenDescriptor);
|
||||
|
||||
return tokenHandler.WriteToken(jwtSecurityToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
global using Xunit;
|
||||
+33
-19
@@ -1,21 +1,35 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0-release-24177-07" />
|
||||
<PackageReference Include="xunit" Version="2.7.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="xunit" Version="2.8.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\HelloShop.ProductService\HelloShop.ProductService.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using AutoMapper;
|
||||
using HelloShop.ProductService.Controllers;
|
||||
using HelloShop.ProductService.Entities.Products;
|
||||
using HelloShop.ProductService.Models.Products;
|
||||
using HelloShop.ProductService.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
|
||||
namespace HelloShop.ProductService.UnitTests
|
||||
{
|
||||
public class MockProductsControllerTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetProductReturnsNotFoundIfNotExists()
|
||||
{
|
||||
// Arrange
|
||||
Mock<IProductService> mock = new();
|
||||
|
||||
mock.Setup(m => m.FindAsync(It.Is<int>(id => id == 1), It.IsAny<CancellationToken>())).ReturnsAsync((Product?)null);
|
||||
|
||||
// Act
|
||||
IMapper mapper = new Mapper(new MapperConfiguration(cfg => cfg.CreateMap<Product, ProductDetailsResponse>()));
|
||||
MockProductsController mockProductsController = new(mock.Object, mapper);
|
||||
ActionResult<ProductDetailsResponse> result = await mockProductsController.GetProduct(1);
|
||||
|
||||
//Assert
|
||||
Assert.IsType<NotFoundResult>(result.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAllReturnsPorductListItems()
|
||||
{
|
||||
// Arrange
|
||||
Mock<IProductService> mock = new();
|
||||
|
||||
mock.Setup(m => m.GetAllAsync(It.IsAny<CancellationToken>())).ReturnsAsync([new Product { Id = 1, Name = "Product 1", Price = 10 }, new Product { Id = 2, Name = "Product 2", Price = 20 }]);
|
||||
|
||||
// Act
|
||||
IMapper mapper = new Mapper(new MapperConfiguration(cfg => cfg.CreateMap<Product, ProductListItem>()));
|
||||
MockProductsController mockProductsController = new(mock.Object, mapper);
|
||||
ActionResult<IEnumerable<ProductListItem>> result = await mockProductsController.GetProducts();
|
||||
|
||||
//Assert
|
||||
Assert.NotNull(result.Value);
|
||||
|
||||
Assert.Collection(result.Value, productListItem1 =>
|
||||
{
|
||||
Assert.Equal(1, productListItem1.Id);
|
||||
Assert.Equal("Product 1", productListItem1.Name);
|
||||
Assert.Equal(10, productListItem1.Price);
|
||||
}, productListItem2 =>
|
||||
{
|
||||
Assert.Equal(2, productListItem2.Id);
|
||||
Assert.Equal("Product 2", productListItem2.Name);
|
||||
Assert.Equal(20, productListItem2.Price);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using AutoMapper;
|
||||
using HelloShop.ProductService.AutoMapper;
|
||||
using HelloShop.ProductService.Entities.Products;
|
||||
using HelloShop.ProductService.Models.Products;
|
||||
using HelloShop.ProductService.UnitTests.Utilities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HelloShop.ProductService.UnitTests
|
||||
{
|
||||
public class ProductsControllerTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetProductByIdReturnsProductDetailsResponse()
|
||||
{
|
||||
// Arrange
|
||||
await using EntityFrameworks.ProductServiceDbContext dbContext = new FakeDbContextFactory().CreateDbContext();
|
||||
|
||||
await dbContext.AddAsync(new Product { Id = 1, Name = "Product 1", Price = 10 });
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
IMapper mapper = new MapperConfiguration(configure => configure.CreateMap<Product, ProductDetailsResponse>()).CreateMapper();
|
||||
|
||||
ProductsController productsController = new(dbContext, mapper);
|
||||
|
||||
// Act
|
||||
ActionResult<ProductDetailsResponse> result = await productsController.GetProduct(1);
|
||||
|
||||
//Assert
|
||||
Assert.Equal(10, result.Value?.Price);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Product 1", 10)]
|
||||
[InlineData("Product 2", 20)]
|
||||
[InlineData("Product 3", 30)]
|
||||
public async Task PostProductReturnsProductDetailsResponse(string productName, decimal price)
|
||||
{
|
||||
// Arrange
|
||||
await using EntityFrameworks.ProductServiceDbContext dbContext = new FakeDbContextFactory().CreateDbContext();
|
||||
|
||||
IMapper mapper = new MapperConfiguration(configure => configure.AddProfile<ProductsMapConfiguration>()).CreateMapper();
|
||||
|
||||
ProductsController productsController = new(dbContext, mapper);
|
||||
|
||||
// Act
|
||||
ActionResult<ProductDetailsResponse> createdAtActionResult = await productsController.PostProduct(new ProductCreateRequest { Name = productName, Price = price });
|
||||
ProductDetailsResponse? result = (createdAtActionResult?.Result as CreatedAtActionResult)?.Value as ProductDetailsResponse;
|
||||
|
||||
//Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.Equal(price, result?.Price);
|
||||
Assert.Equal(productName, result?.Name);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# Unit test bast practices
|
||||
|
||||
## Unit testing best practices with .NET Core and .NET Standard
|
||||
|
||||
https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices
|
||||
|
||||
## Testing without your production database system
|
||||
|
||||
https://learn.microsoft.com/en-us/ef/core/testing/testing-without-the-database
|
||||
|
||||
## Unit test controller logic in ASP.NET Core
|
||||
|
||||
https://learn.microsoft.com/en-us/ef/core/testing/testing-without-the-database
|
||||
|
||||
## Unit and integration tests in Minimal API apps
|
||||
|
||||
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/test-min-api
|
||||
|
||||
## Integration tests in ASP.NET Core
|
||||
|
||||
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests
|
||||
|
||||
## Use Moq with xUnit in .NET Core unit tests
|
||||
|
||||
https://github.com/devlooped/moq
|
||||
|
||||
## Test gRPC services in ASP.NET Core
|
||||
|
||||
https://learn.microsoft.com/en-us/aspnet/core/grpc/test-services
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace HelloShop.ProductService.UnitTests
|
||||
{
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ProductService.EntityFrameworks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HelloShop.ProductService.UnitTests.Utilities
|
||||
{
|
||||
public class FakeDbContextFactory : IDbContextFactory<ProductServiceDbContext>
|
||||
{
|
||||
public ProductServiceDbContext CreateDbContext()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<ProductServiceDbContext>().UseInMemoryDatabase($"InMemoryTestDb-{DateTimeOffset.UtcNow.ToFileTime()}").Options;
|
||||
|
||||
return new ProductServiceDbContext(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user