refactor integrationTests

This commit is contained in:
ngfrolov 2024-01-19 17:49:09 +05:00
parent 6178061b49
commit 9a2762ba60
Signed by untrusted user who does not match committer: ng.frolov
GPG Key ID: E99907A0357B29A7
10 changed files with 295 additions and 85 deletions

View File

@ -10,31 +10,14 @@ namespace AsbCloudWebApi.IntegrationTests;
public abstract class BaseIntegrationTest : IClassFixture<WebAppFactoryFixture>
{
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<IAsbCloudDbContext>();
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<IAdminDepositClient>(httpClient, refitSettings);
}
this.factory = factory;
}
}

View File

@ -24,4 +24,4 @@ public interface IAdminDepositClient
[Delete(BaseRoute + "/{id}")]
Task<IApiResponse<int>> DeleteAsync(int id);
}
}

View File

@ -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<IApiResponse<int>> InsertRangeAsync(int idWell, IEnumerable<ProcessMapPlanDrillingDto> dtos);
[Post($"{BaseRoute}/replace")]
Task<IApiResponse<int>> ClearAndInsertRangeAsync(int idWell, IEnumerable<ProcessMapPlanDrillingDto> dtos);
[Delete(BaseRoute)]
Task<IApiResponse<int>> DeleteRangeAsync(int idWell, IEnumerable<int> ids);
[Get(BaseRoute)]
Task<IApiResponse<IEnumerable<ProcessMapPlanDrillingDto>>> GetAsync(int idWell, [FromQuery] ProcessMapPlanBaseRequest request);
[Get($"{BaseRoute}/changeLog")]
Task<IApiResponse<IEnumerable<ProcessMapPlanDrillingDto>>> GetChangeLogAsync(int idWell, [FromQuery] DateOnly? date);
[Get($"{BaseRoute}/dates")]
Task<IApiResponse<IEnumerable<DateOnly>>> GetDatesChangeAsync(int idWell);
[Put(BaseRoute)]
Task<IApiResponse<int>> UpdateRangeAsync(int idWell, IEnumerable<ProcessMapPlanDrillingDto> dtos);
}

View File

@ -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<IAdminDepositClient>();
}
[Fact]
public async Task InsertAsync_ReturnsSuccess_WhenNewItemIsValid()
{
//arrange
var expectedDto = DepositTestFaker.GetDeposit().Adapt<DepositBaseDto>();
var expectedDto = EntitiesFaker.Deposit.Generate().Adapt<DepositBaseDto>();
//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<DepositBaseDto>();
var dto = EntitiesFaker.Deposit.Generate().Adapt<DepositBaseDto>();
//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<DepositBaseDto>();
var dto = EntitiesFaker.Deposit.Generate().Adapt<DepositBaseDto>();
//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<DepositBaseDto>();
var insertResponse = await adminDepositClient.InsertAsync(dto);
var dto = EntitiesFaker.Deposit.Generate().Adapt<DepositBaseDto>();
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<DepositBaseDto>();
var insertResponse = await adminDepositClient.InsertAsync(dto);
var id = insertResponse.Content;
var entity = await dbContext.Deposits.FirstAsync();
var expected = entity.Adapt<DepositBaseDto>();
//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<DepositBaseDto>();
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<DepositBaseDto>();
var insertResponse = await adminDepositClient.InsertAsync(dto);
var dto = EntitiesFaker.Deposit.Generate().Adapt<DepositBaseDto>();
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);

View File

@ -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<IProcessMapPlanDrillingClient>();
}
[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<ProcessMapPlanDrilling>()
.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<ProcessMapPlanDrillingDto>();
var excludeProps = new[] {
nameof(ProcessMapPlanDrillingDto.Id),
nameof(ProcessMapPlanDrillingDto.IdAuthor),
nameof(ProcessMapPlanDrillingDto.Creation),
};
MatchHelper.Match(expected, actual, excludeProps);
}
}

View File

@ -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}
};
}
}

View File

@ -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<Deposit> GetDeposits(int count) =>
GetDepositFaker().Generate(count);
private static Faker<Deposit> GetDepositFaker() =>
new Faker<Deposit>()
.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()
});
}

View File

@ -0,0 +1,40 @@
using AsbCloudDb.Model;
using Bogus;
namespace AsbCloudWebApi.IntegrationTests.TestFakers;
public static class EntitiesFaker
{
public static Faker<Deposit> Deposit { get; } = new Faker<Deposit>()
.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> Cluster { get; } = new Faker<Cluster>()
.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> Well { get; } = new Faker<Well>()
.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()
});
}

View File

@ -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<Startup>,
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<Startup>,
using var scope = Services.CreateScope();
var scopedServices = scope.ServiceProvider;
var dbContext = scopedServices.GetRequiredService<AsbCloudDbContext>();
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<AsbCloudDbContext>();
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<T>()
{
var httpClient = GetAuthorizedHttpClient();
return RestService.For<T>(httpClient, refitSettings);
}
}

View File

@ -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