diff --git a/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs b/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs index 7017e79c..a31e8500 100644 --- a/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs +++ b/AsbCloudWebApi.IntegrationTests/BaseIntegrationTest.cs @@ -10,31 +10,14 @@ namespace AsbCloudWebApi.IntegrationTests; public abstract class BaseIntegrationTest : IClassFixture { - private readonly IServiceScope scope; - private readonly HttpClient httpClient; - + protected readonly IServiceScope scope; protected readonly IAsbCloudDbContext dbContext; + protected readonly WebAppFactoryFixture factory; - protected IAdminDepositClient adminDepositClient; - - protected BaseIntegrationTest(WebAppFactoryFixture factory) + protected BaseIntegrationTest(WebAppFactoryFixture factory) { scope = factory.Services.CreateScope(); - httpClient = factory.CreateClient(); - dbContext = scope.ServiceProvider.GetRequiredService(); - - var jwtToken = ApiTokenHelper.GetAdminUserToken(); - httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); - - var jsonSerializerOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - PropertyNameCaseInsensitive = true - }; - - var refitSettings = new RefitSettings(new SystemTextJsonContentSerializer(jsonSerializerOptions)); - - adminDepositClient = RestService.For(httpClient, refitSettings); - } + this.factory = factory; + } } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs index ddc32005..bd47235b 100644 --- a/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs +++ b/AsbCloudWebApi.IntegrationTests/Clients/IAdminDepositClient.cs @@ -24,4 +24,4 @@ public interface IAdminDepositClient [Delete(BaseRoute + "/{id}")] Task> DeleteAsync(int id); -} \ No newline at end of file +} diff --git a/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs b/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs new file mode 100644 index 00000000..f1eb677e --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Clients/IProcessMapPlanDrillingClient.cs @@ -0,0 +1,32 @@ +using AsbCloudApp.Data.ProcessMapPlan; +using AsbCloudApp.Requests; +using Microsoft.AspNetCore.Mvc; +using Refit; + +namespace AsbCloudWebApi.IntegrationTests.Clients; + +public interface IProcessMapPlanDrillingClient +{ + private const string BaseRoute = "/api/well/{idWell}/ProcessMapPlanDrilling"; + + [Post(BaseRoute)] + Task> InsertRangeAsync(int idWell, IEnumerable dtos); + + [Post($"{BaseRoute}/replace")] + Task> ClearAndInsertRangeAsync(int idWell, IEnumerable dtos); + + [Delete(BaseRoute)] + Task> DeleteRangeAsync(int idWell, IEnumerable ids); + + [Get(BaseRoute)] + Task>> GetAsync(int idWell, [FromQuery] ProcessMapPlanBaseRequest request); + + [Get($"{BaseRoute}/changeLog")] + Task>> GetChangeLogAsync(int idWell, [FromQuery] DateOnly? date); + + [Get($"{BaseRoute}/dates")] + Task>> GetDatesChangeAsync(int idWell); + + [Put(BaseRoute)] + Task> UpdateRangeAsync(int idWell, IEnumerable dtos); +} diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs b/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs index 81c76420..f05c71ab 100644 --- a/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs +++ b/AsbCloudWebApi.IntegrationTests/Controllers/AdminDepositControllerTests.cs @@ -1,5 +1,6 @@ using System.Net; using AsbCloudApp.Data; +using AsbCloudWebApi.IntegrationTests.Clients; using AsbCloudWebApi.IntegrationTests.TestFakers; using Mapster; using Microsoft.EntityFrameworkCore; @@ -9,19 +10,22 @@ namespace AsbCloudWebApi.IntegrationTests.Controllers; public class AdminDepositControllerTests : BaseIntegrationTest { - public AdminDepositControllerTests(WebAppFactoryFixture factory) - : base(factory) - { - } + protected IAdminDepositClient client; + + public AdminDepositControllerTests(WebAppFactoryFixture factory) + : base(factory) + { + client = factory.GetAuthorizedHttpClient(); + } [Fact] public async Task InsertAsync_ReturnsSuccess_WhenNewItemIsValid() { //arrange - var expectedDto = DepositTestFaker.GetDeposit().Adapt(); + var expectedDto = EntitiesFaker.Deposit.Generate().Adapt(); //act - var response = await adminDepositClient.InsertAsync(expectedDto); + var response = await client.InsertAsync(expectedDto); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -38,10 +42,10 @@ public class AdminDepositControllerTests : BaseIntegrationTest public async Task InsertRangeAsync_ReturnsSuccess_WhenAllNewItemsIsValid() { //arrange - var dto = DepositTestFaker.GetDeposit().Adapt(); + var dto = EntitiesFaker.Deposit.Generate().Adapt(); //act - var responce = await adminDepositClient.InsertRangeAsync(new[] { dto }); + var responce = await client.InsertRangeAsync(new[] { dto }); //assert Assert.Equal(HttpStatusCode.OK, responce.StatusCode); @@ -58,10 +62,10 @@ public class AdminDepositControllerTests : BaseIntegrationTest public async Task UpdateAsync_ReturnsBadRequest_WhenUpdatedItemHasInvalidId() { //arrange - var dto = DepositTestFaker.GetDeposit().Adapt(); + var dto = EntitiesFaker.Deposit.Generate().Adapt(); //act - var response = await adminDepositClient.UpdateAsync(dto); + var response = await client.UpdateAsync(dto); //assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -71,8 +75,8 @@ public class AdminDepositControllerTests : BaseIntegrationTest public async Task UpdateAsync_ReturnsSuccess_WhenUpdatedItemIsValid() { //arrange - var dto = DepositTestFaker.GetDeposit().Adapt(); - var insertResponse = await adminDepositClient.InsertAsync(dto); + var dto = EntitiesFaker.Deposit.Generate().Adapt(); + var insertResponse = await client.InsertAsync(dto); dto.Id = insertResponse.Content; dto.Caption = "Test"; @@ -85,7 +89,7 @@ public class AdminDepositControllerTests : BaseIntegrationTest }; //act - var response = await adminDepositClient.UpdateAsync(dto); + var response = await client.UpdateAsync(dto); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -101,22 +105,17 @@ public class AdminDepositControllerTests : BaseIntegrationTest public async Task GetOrDefaultAsync_ReturnsSuccess_WhenIdIsValid() { //arrange - var dto = DepositTestFaker.GetDeposit().Adapt(); - var insertResponse = await adminDepositClient.InsertAsync(dto); - var id = insertResponse.Content; + var entity = await dbContext.Deposits.FirstAsync(); + var expected = entity.Adapt(); - //act - var response = await adminDepositClient.GetOrDefaultAsync(id); + //act + var response = await client.GetOrDefaultAsync(entity.Id); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(response.Content); - var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == response.Content.Id); - var deposit = entity?.Adapt(); - - var excludeProps = new[] { nameof(DepositBaseDto.Id) }; - MatchHelper.Match(dto, deposit, excludeProps); + MatchHelper.Match(expected, response.Content); } [Fact] @@ -126,7 +125,7 @@ public class AdminDepositControllerTests : BaseIntegrationTest const int id = 0; //act - var responce = await adminDepositClient.GetOrDefaultAsync(id); + var responce = await client.GetOrDefaultAsync(id); //assert Assert.Equal(HttpStatusCode.NoContent, responce.StatusCode); @@ -136,7 +135,7 @@ public class AdminDepositControllerTests : BaseIntegrationTest public async Task GetAllAsync_ReturnsSuccess() { //act - var response = await adminDepositClient.GetAllAsync(); + var response = await client.GetAllAsync(); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -156,12 +155,12 @@ public class AdminDepositControllerTests : BaseIntegrationTest public async Task DeleteAsync_ReturnsSuccess_WhenIdIsValid() { //arrange - var dto = DepositTestFaker.GetDeposit().Adapt(); - var insertResponse = await adminDepositClient.InsertAsync(dto); + var dto = EntitiesFaker.Deposit.Generate().Adapt(); + var insertResponse = await client.InsertAsync(dto); var id = insertResponse.Content; //act - var response = await adminDepositClient.DeleteAsync(id); + var response = await client.DeleteAsync(id); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -178,7 +177,7 @@ public class AdminDepositControllerTests : BaseIntegrationTest const int id = 0; //act - var response = await adminDepositClient.DeleteAsync(id); + var response = await client.DeleteAsync(id); //assert Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); diff --git a/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs b/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs new file mode 100644 index 00000000..4994b2c6 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Controllers/ProcessMapPlanDrillingControllerTest.cs @@ -0,0 +1,82 @@ +using AsbCloudApp.Data.ProcessMapPlan; +using AsbCloudDb.Model.ProcessMaps; +using AsbCloudWebApi.IntegrationTests.Clients; +using Mapster; +using Microsoft.EntityFrameworkCore; +using System.Net; +using Xunit; + +namespace AsbCloudWebApi.IntegrationTests.Controllers; + +public class ProcessMapPlanDrillingControllerTest: BaseIntegrationTest +{ + private IProcessMapPlanDrillingClient client; + + readonly ProcessMapPlanDrillingDto dto = new (){ + Id = 0, + IdAuthor = 0, + IdEditor = null, + Creation = new(), + Obsolete = null, + IdState = 0, + IdPrevious = null, + + IdWell = 1, + IdWellSectionType = 1, + DepthStart = 0.5, + DepthEnd = 1.5, + + IdMode = 1, + AxialLoadPlan = 2.718281, + AxialLoadLimitMax = 3.1415926, + DeltaPressurePlan = 4, + DeltaPressureLimitMax = 5, + TopDriveTorquePlan = 6, + TopDriveTorqueLimitMax = 7, + TopDriveSpeedPlan = 8, + TopDriveSpeedLimitMax = 9, + FlowPlan = 10, + FlowLimitMax = 11, + RopPlan = 12, + UsageSaub = 13, + UsageSpin = 14, + Comment = "это тестовая запись", + }; + + public ProcessMapPlanDrillingControllerTest(WebAppFactoryFixture factory) : base(factory) + { + client = factory.GetAuthorizedHttpClient(); + } + + [Fact] + public async Task InsertRangeAsync_ReturnsSuccess_WhenNewItemIsValid() + { + //arrange + var expected = dto; + + //act + var response = await client.InsertRangeAsync(dto.IdWell, new[] { expected }); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(1, response.Content); + + var entity = await dbContext.Set() + .Where(p => p.AxialLoadPlan == dto.AxialLoadPlan) + .Where(p => p.AxialLoadLimitMax == dto.AxialLoadLimitMax) + .Where(p => p.Comment == dto.Comment) + .Where(p => p.IdWell == dto.IdWell) + .FirstOrDefaultAsync(); + + Assert.NotNull(entity); + + var actual = entity.Adapt(); + + var excludeProps = new[] { + nameof(ProcessMapPlanDrillingDto.Id), + nameof(ProcessMapPlanDrillingDto.IdAuthor), + nameof(ProcessMapPlanDrillingDto.Creation), + }; + MatchHelper.Match(expected, actual, excludeProps); + } +} diff --git a/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs b/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs new file mode 100644 index 00000000..3458bbd1 --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/Data/Defaults.cs @@ -0,0 +1,63 @@ +using AsbCloudDb.Model; + +namespace AsbCloudWebApi.IntegrationTests.Data +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2211:Поля, не являющиеся константами, не должны быть видимыми", Justification = "<Ожидание>")] + public static class Defaults + { + public static Deposit[] Deposits = new Deposit[] { + new() + { + Id = 1, + Caption = "Deposit1", + Latitude = 10, + Longitude = 20, + Timezone = new SimpleTimezone{ + Hours = 1 + } + } + }; + + public static Cluster[] Clusters = new Cluster[] { + new() + { + Id = 1, + IdDeposit = Deposits[0].Id, + Caption = "Cluster1", + Latitude = 10, + Longitude = 20, + Timezone = new SimpleTimezone{ + Hours = 1 + } + } + }; + + public static Well[] Wells = new Well[] { + new() + { + Id = 1, + IdCluster = Clusters[0].Id, + IdWellType = 1, + IdState = 1, + Caption = "Well1", + Latitude = 10, + Longitude = 20, + IdTelemetry = null, + Timezone = new SimpleTimezone{ + Hours = 1 + } + } + }; + + public static RelationCompanyWell[] RelationsCompanyWell = new RelationCompanyWell[] + { + new(){IdCompany= 1, IdWell = Wells[0].Id}, + }; + + public static RelationUserUserRole[] RelationsUserUserRole = new RelationUserUserRole[] + { + new(){ IdUserRole= 1, IdUser = 1} + }; + + } +} diff --git a/AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs b/AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs deleted file mode 100644 index c2f6e098..00000000 --- a/AsbCloudWebApi.IntegrationTests/TestFakers/DepositTestFaker.cs +++ /dev/null @@ -1,25 +0,0 @@ -using AsbCloudDb.Model; -using Bogus; - -namespace AsbCloudWebApi.IntegrationTests.TestFakers; - -public static class DepositTestFaker -{ - public static Deposit GetDeposit() => - GetDepositFaker().Generate(); - - public static IEnumerable GetDeposits(int count) => - GetDepositFaker().Generate(count); - - private static Faker GetDepositFaker() => - new Faker() - .RuleFor(d => d.Id, 0) - .RuleFor(d => d.Caption, f => f.Random.String2(1, 50)) - .RuleFor(d => d.Latitude, f => f.Random.Int(-90, 90)) - .RuleFor(d => d.Longitude, f => f.Random.Int(-180, 180)) - .RuleFor(d => d.Timezone, f => new SimpleTimezone - { - Hours = f.Random.Int(1, 12), - IsOverride = f.Random.Bool() - }); -} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/TestFakers/EntitiesFaker.cs b/AsbCloudWebApi.IntegrationTests/TestFakers/EntitiesFaker.cs new file mode 100644 index 00000000..2cbe800e --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/TestFakers/EntitiesFaker.cs @@ -0,0 +1,40 @@ +using AsbCloudDb.Model; +using Bogus; + +namespace AsbCloudWebApi.IntegrationTests.TestFakers; + +public static class EntitiesFaker +{ + public static Faker Deposit { get; } = new Faker() + .RuleFor(d => d.Id, 0) + .RuleFor(d => d.Caption, f => f.Random.String2(1, 50)) + .RuleFor(d => d.Latitude, f => f.Random.Double(-90, 90)) + .RuleFor(d => d.Longitude, f => f.Random.Double(-180, 180)) + .RuleFor(d => d.Timezone, f => new SimpleTimezone + { + Hours = f.Random.Int(1, 12), + IsOverride = f.Random.Bool() + }); + + public static Faker Cluster { get; } = new Faker() + .RuleFor(d => d.Id, 0) + .RuleFor(d => d.Caption, f => f.Random.String2(1, 50)) + .RuleFor(d => d.Latitude, f => f.Random.Double(-90, 90)) + .RuleFor(d => d.Longitude, f => f.Random.Double(-180, 180)) + .RuleFor(d => d.Timezone, f => new SimpleTimezone + { + Hours = f.Random.Int(1, 12), + IsOverride = f.Random.Bool() + }); + + public static Faker Well { get; } = new Faker() + .RuleFor(d => d.Id, 0) + .RuleFor(d => d.Caption, f => f.Random.String2(1, 50)) + .RuleFor(d => d.Latitude, f => f.Random.Double(-90, 90)) + .RuleFor(d => d.Longitude, f => f.Random.Double(-180, 180)) + .RuleFor(d => d.Timezone, f => new SimpleTimezone + { + Hours = f.Random.Int(1, 12), + IsOverride = f.Random.Bool() + }); +} \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs b/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs index a3f578ac..672ebe55 100644 --- a/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs +++ b/AsbCloudWebApi.IntegrationTests/WebAppFactoryFixture.cs @@ -6,6 +6,10 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using ProtoBuf.Serializers; +using Refit; +using System.Net.Http.Headers; +using System.Text.Json; using Xunit; namespace AsbCloudWebApi.IntegrationTests; @@ -13,12 +17,20 @@ namespace AsbCloudWebApi.IntegrationTests; public class WebAppFactoryFixture : WebApplicationFactory, IAsyncLifetime { + private static readonly JsonSerializerOptions jsonSerializerOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true + }; + + private static readonly RefitSettings refitSettings = new RefitSettings(new SystemTextJsonContentSerializer(jsonSerializerOptions)); + protected override void ConfigureWebHost(IWebHostBuilder builder) { var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); - var connectionString = configuration.GetConnectionString("TestConnection"); + var connectionString = configuration.GetConnectionString("TestConnection")!; builder.ConfigureServices(services => { @@ -37,19 +49,41 @@ public class WebAppFactoryFixture : WebApplicationFactory, using var scope = Services.CreateScope(); var scopedServices = scope.ServiceProvider; var dbContext = scopedServices.GetRequiredService(); - - dbContext.Database.EnsureCreatedAndMigrated(); - - dbContext.Deposits.AddRange(DepositTestFaker.GetDeposits(15)); - await dbContext.SaveChangesAsync(); + dbContext.Database.EnsureDeleted(); + dbContext.Database.EnsureCreatedAndMigrated(); + await FillBaseDatasets(dbContext); } - public new async Task DisposeAsync() + private static async Task FillBaseDatasets(AsbCloudDbContext dbContext) + { + dbContext.AddRange(Data.Defaults.Deposits); + dbContext.AddRange(Data.Defaults.Clusters); + dbContext.AddRange(Data.Defaults.Wells); + dbContext.AddRange(Data.Defaults.RelationsCompanyWell); + await dbContext.SaveChangesAsync(); + } + + public new async Task DisposeAsync() { using var scope = Services.CreateScope(); var scopedServices = scope.ServiceProvider; var dbContext = scopedServices.GetRequiredService(); await dbContext.Database.EnsureDeletedAsync(); - } + } + + public HttpClient GetAuthorizedHttpClient() + { + var httpClient = CreateClient(); + var jwtToken = ApiTokenHelper.GetAdminUserToken(); + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); + return httpClient; + } + + public T GetAuthorizedHttpClient() + { + var httpClient = GetAuthorizedHttpClient(); + return RestService.For(httpClient, refitSettings); + } + } \ No newline at end of file diff --git a/AsbCloudWebApi.IntegrationTests/readme.md b/AsbCloudWebApi.IntegrationTests/readme.md new file mode 100644 index 00000000..6449d67a --- /dev/null +++ b/AsbCloudWebApi.IntegrationTests/readme.md @@ -0,0 +1,2 @@ +Статья от ms https://learn.microsoft.com/ru-ru/aspnet/core/test/integration-tests?view=aspnetcore-6.0 +refit https://github.com/reactiveui/refit \ No newline at end of file