tests(infra,api): refactor to allow further config of TestApi

This commit is contained in:
Stevan Freeborn
2026-03-08 09:15:45 -05:00
parent 870baf7b6c
commit 1a4f7fac8d
12 changed files with 123 additions and 83 deletions
+1 -2
View File
@@ -81,7 +81,6 @@ dotnet_remove_unnecessary_suppression_exclusions = none
# analyzer settings # analyzer settings
dotnet_diagnostic.IDE0058.severity = none dotnet_diagnostic.IDE0058.severity = none
dotnet_diagnostic.IDE0053.severity = when_on_single_line:suggestion
dotnet_diagnostic.IDE0100.severity = none dotnet_diagnostic.IDE0100.severity = none
dotnet_diagnostic.CA1515.severity = none dotnet_diagnostic.CA1515.severity = none
dotnet_diagnostic.CA1848.severity = none dotnet_diagnostic.CA1848.severity = none
@@ -95,7 +94,7 @@ csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_expression_bodied_accessors = true:silent csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:suggestion csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion
csharp_style_expression_bodied_local_functions = false:silent csharp_style_expression_bodied_local_functions = false:silent
csharp_style_expression_bodied_methods = false:silent csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_operators = false:silent
@@ -13,7 +13,10 @@ internal sealed class HttpRequestBuilder
{ {
} }
public static HttpRequestBuilder New() => new(); public static HttpRequestBuilder New()
{
return new();
}
public HttpRequestBuilder WithMethod(HttpMethod method) public HttpRequestBuilder WithMethod(HttpMethod method)
{ {
+68
View File
@@ -2,6 +2,8 @@ namespace FiscalOS.API.Tests.Infra;
public class TestApi : WebApplicationFactory<Program> public class TestApi : WebApplicationFactory<Program>
{ {
private readonly List<Action<IWebHostBuilder>> _additionalConfigs = [];
protected override void ConfigureWebHost(IWebHostBuilder builder) protected override void ConfigureWebHost(IWebHostBuilder builder)
{ {
base.ConfigureWebHost(builder); base.ConfigureWebHost(builder);
@@ -25,5 +27,71 @@ public class TestApi : WebApplicationFactory<Program>
c.AddSingleton<IKeyRing>(TestKeyRing.From); c.AddSingleton<IKeyRing>(TestKeyRing.From);
}); });
foreach (var config in _additionalConfigs)
{
config(builder);
}
}
public TestApi WithAdditionalConfig(Action<IWebHostBuilder> configuration)
{
var newApi = new TestApi();
newApi._additionalConfigs.AddRange(_additionalConfigs);
newApi._additionalConfigs.Add(configuration);
return newApi;
}
public async Task ExecuteAsync(Func<DbContext, CancellationToken, Task> action, CancellationToken ct)
{
await using var scope = Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await action(context, ct);
}
public async Task ExecuteAsync(Func<DbContext, CancellationToken, IServiceProvider, Task> action, CancellationToken ct)
{
await using var scope = Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await action(context, ct, scope.ServiceProvider);
}
public async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, Task<T>> action, CancellationToken ct)
{
await using var scope = Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return await action(context, ct);
}
public async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, IServiceProvider, Task<T>> action, CancellationToken ct)
{
await using var scope = Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return await action(context, ct, scope.ServiceProvider);
}
public async Task EnsureDbCreatedAsync()
{
await ExecuteAsync(static async (context, ct) =>
{
await context.Database.EnsureCreatedAsync(ct);
}, TestContext.Current.CancellationToken);
}
public async Task EnsureDbDeletedAsync()
{
await ExecuteAsync(static async (context, ct) =>
{
await context.Database.EnsureDeletedAsync(ct);
}, TestContext.Current.CancellationToken);
}
public override async ValueTask DisposeAsync()
{
await EnsureDbDeletedAsync();
await base.DisposeAsync();
GC.SuppressFinalize(this);
} }
} }
@@ -1,3 +1,6 @@
using FiscalOS.Core.Queuing;
using FiscalOS.Infra.Transactions.Plaid;
using Account = FiscalOS.Core.Accounts.Account; using Account = FiscalOS.Core.Accounts.Account;
using Institution = FiscalOS.Core.Accounts.Institution; using Institution = FiscalOS.Core.Accounts.Institution;
@@ -31,7 +34,6 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."], ["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."],
["PlaidAccountId"] = ["The PlaidAccountId field is required."], ["PlaidAccountId"] = ["The PlaidAccountId field is required."],
["PlaidAccountName"] = ["The PlaidAccountName field is required."], ["PlaidAccountName"] = ["The PlaidAccountName field is required."],
["AccountCurrencyCode"] = ["The AccountCurrencyCode field is required."],
}); });
} }
@@ -124,7 +126,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Add_WhenCalledWithPlaidInstitutionIdThatHasNotBeenAdded_ItShouldReturn400WithProblemDetails() public async Task Add_WhenCalledWithPlaidInstitutionIdThatHasNotBeenAdded_ItShouldReturn400WithProblemDetails()
{ {
var user = await ExecuteAsync(static async (context, ct, sp) => var user = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -161,7 +163,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Add_WhenCalledWithPlaidAccountIdThatHasAlreadyBeenAdded_ItShouldReturn409WithProblemDetails() public async Task Add_WhenCalledWithPlaidAccountIdThatHasAlreadyBeenAdded_ItShouldReturn409WithProblemDetails()
{ {
var (user, institution, account) = await ExecuteAsync(static async (context, ct, sp) => var (user, institution, account) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -212,7 +214,18 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Add_WhenCalledWithNewAccount_ItShouldReturn200() public async Task Add_WhenCalledWithNewAccount_ItShouldReturn200()
{ {
var (user, institution) = await ExecuteAsync(async (context, ct, sp) => var mockQueue = new Mock<IAsyncQueue<SyncUpdatesQueueItem>>();
await using var testApi = Api
.WithAdditionalConfig(whb =>
{
whb.ConfigureTestServices(s =>
{
s.AddSingleton(mockQueue.Object);
});
});
var (user, institution) = await testApi.ExecuteAsync(async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -256,11 +269,13 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
}) })
.Build(); .Build();
var response = await Client.SendAsync(request, TestContext.Current.CancellationToken); var client = testApi.CreateClient();
var response = await client.SendAsync(request, TestContext.Current.CancellationToken);
response.StatusCode.Should().Be(HttpStatusCode.OK); response.StatusCode.Should().Be(HttpStatusCode.OK);
var updatedUser = await ExecuteAsync( var updatedUser = await testApi.ExecuteAsync(
async (context, ct) => await context.Set<User>() async (context, ct) => await context.Set<User>()
.Include(u => u.Accounts) .Include(u => u.Accounts)
.ThenInclude(a => a.Metadata) .ThenInclude(a => a.Metadata)
@@ -279,12 +294,9 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
((PlaidAccountMetadata)a.Metadata).PlaidName == newAccountName ((PlaidAccountMetadata)a.Metadata).PlaidName == newAccountName
); );
updatedUser.Accounts.First() mockQueue.Verify(m => m.EnqueueAsync(
.Balances.Should().ContainSingle( It.IsAny<SyncUpdatesQueueItem>(),
b => b.AccountId == updatedUser.Accounts.First().Id && It.IsAny<CancellationToken>()
b.Current == expectedBalance && ), Times.Once());
b.Available == expectedBalance &&
b.CurrencyCode == expectedCurrencyCode
);
} }
} }
@@ -42,7 +42,7 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Login_WhenUserExistsButPasswordIsIncorrect_ItShouldReturn401WithProblemDetails() public async Task Login_WhenUserExistsButPasswordIsIncorrect_ItShouldReturn401WithProblemDetails()
{ {
await ExecuteAsync(static async (context, ct, sp) => await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -70,7 +70,7 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Login_WhenUserExistsAndPasswordIsCorrect_ItShouldReturn200WithJwtTokenAndSetRefreshCookie() public async Task Login_WhenUserExistsAndPasswordIsCorrect_ItShouldReturn200WithJwtTokenAndSetRefreshCookie()
{ {
await ExecuteAsync(static async (context, ct, sp) => await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -29,7 +29,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Refresh_WhenCalledWithTokenBelongingToDifferentUser_ItShouldReturn403WithProblemDetails() public async Task Refresh_WhenCalledWithTokenBelongingToDifferentUser_ItShouldReturn403WithProblemDetails()
{ {
var (users, refreshToken) = await ExecuteAsync(static async (context, ct, sp) => var (users, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>(); var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
@@ -61,7 +61,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
await response.Should().BeProblemDetails(HttpStatusCode.Forbidden); await response.Should().BeProblemDetails(HttpStatusCode.Forbidden);
var unrevokedTokensCountForUser2 = await ExecuteAsync( var unrevokedTokensCountForUser2 = await Api.ExecuteAsync(
async (context, ct) => await context.Set<RefreshToken>() async (context, ct) => await context.Set<RefreshToken>()
.Include(t => t.User) .Include(t => t.User)
.Where(t => t.UserId == users[1].Id && t.Revoked == false) .Where(t => t.UserId == users[1].Id && t.Revoked == false)
@@ -75,7 +75,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Refresh_WhenCalledWithRevokedRefreshToken_ItShouldReturn400WithProblemDetails() public async Task Refresh_WhenCalledWithRevokedRefreshToken_ItShouldReturn400WithProblemDetails()
{ {
var (user, refreshToken) = await ExecuteAsync(static async (context, ct, sp) => var (user, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>(); var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
@@ -108,7 +108,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Refresh_WhenCalledWithExpiredRefreshToken_ItShouldReturn400WithProblemDetails() public async Task Refresh_WhenCalledWithExpiredRefreshToken_ItShouldReturn400WithProblemDetails()
{ {
var (user, refreshToken) = await ExecuteAsync(static async (context, ct, sp) => var (user, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>(); var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
@@ -142,7 +142,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
[InlineData(-5)] [InlineData(-5)]
public async Task Refresh_WhenCalledWithValidRefreshTokenAndExpiredOrNotExpiredAccessToken_ItShouldReturn200WithNewTokensAndSetRefreshCookie(int accessTokenExpiresAtOffset) public async Task Refresh_WhenCalledWithValidRefreshTokenAndExpiredOrNotExpiredAccessToken_ItShouldReturn200WithNewTokensAndSetRefreshCookie(int accessTokenExpiresAtOffset)
{ {
var (user, refreshToken) = await ExecuteAsync(static async (context, ct, sp) => var (user, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>(); var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
@@ -174,7 +174,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
response.Should().HaveSetCookieHeader("fiscalos_refresh_cookie"); response.Should().HaveSetCookieHeader("fiscalos_refresh_cookie");
await response.Should().BeJsonContentOfType<API.Auth.Refresh.Response>(HttpStatusCode.OK); await response.Should().BeJsonContentOfType<API.Auth.Refresh.Response>(HttpStatusCode.OK);
var oldRefreshTokenInDb = await ExecuteAsync( var oldRefreshTokenInDb = await Api.ExecuteAsync(
async (context, ct) => await context.Set<RefreshToken>() async (context, ct) => await context.Set<RefreshToken>()
.Include(t => t.User) .Include(t => t.User)
.Where(t => t.UserId == user.Id && t.Token == refreshToken.Token && t.Revoked == true) .Where(t => t.UserId == user.Id && t.Token == refreshToken.Token && t.Revoked == true)
@@ -184,7 +184,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
oldRefreshTokenInDb.Should().NotBeNull(); oldRefreshTokenInDb.Should().NotBeNull();
var newRefreshTokenInDb = await ExecuteAsync( var newRefreshTokenInDb = await Api.ExecuteAsync(
async (context, ct) => await context.Set<RefreshToken>() async (context, ct) => await context.Set<RefreshToken>()
.Include(t => t.User) .Include(t => t.User)
.Where(t => t.UserId == user.Id && t.Revoked == false && t.Token != refreshToken.Token) .Where(t => t.UserId == user.Id && t.Revoked == false && t.Token != refreshToken.Token)
@@ -92,7 +92,7 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Connect_WhenCalledWithPlaidInstitutionIdThatIsAlreadyConnected_ItShouldReturn409WithProblemDetails() public async Task Connect_WhenCalledWithPlaidInstitutionIdThatIsAlreadyConnected_ItShouldReturn409WithProblemDetails()
{ {
var (user, institution) = await ExecuteAsync(static async (context, ct, sp) => var (user, institution) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -136,7 +136,7 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
{ {
var plaidInstitutionId = "ins_109508"; var plaidInstitutionId = "ins_109508";
var (user, publicToken) = await ExecuteAsync(async (context, ct, sp) => var (user, publicToken) = await Api.ExecuteAsync(async (context, ct, sp) =>
{ {
var plaidClient = sp.GetRequiredService<PlaidClient>(); var plaidClient = sp.GetRequiredService<PlaidClient>();
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
@@ -171,7 +171,7 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
response.StatusCode.Should().Be(HttpStatusCode.OK); response.StatusCode.Should().Be(HttpStatusCode.OK);
var updatedUser = await ExecuteAsync( var updatedUser = await Api.ExecuteAsync(
async (context, ct) => await context.Set<User>() async (context, ct) => await context.Set<User>()
.Include(u => u.Institutions) .Include(u => u.Institutions)
.ThenInclude(i => i.Metadata) .ThenInclude(i => i.Metadata)
@@ -39,7 +39,7 @@ public class GetAvailableTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task GetAvailable_WhenCalledWithNonExistentInstitutionId_ItShouldReturn404WithProblemDetails() public async Task GetAvailable_WhenCalledWithNonExistentInstitutionId_ItShouldReturn404WithProblemDetails()
{ {
var user = await ExecuteAsync(static async (context, ct, sp) => var user = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -65,7 +65,7 @@ public class GetAvailableTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task GetAvailable_WhenCalledWithConnectedInstitution_ItShouldReturn200WithAvailableAccounts() public async Task GetAvailable_WhenCalledWithConnectedInstitution_ItShouldReturn200WithAvailableAccounts()
{ {
var (user, institution, expectedAccounts) = await ExecuteAsync(static async (context, ct, sp) => var (user, institution, expectedAccounts) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -36,7 +36,7 @@ public class GetTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Get_WhenCalledByUser_ItShouldReturn200WithListOfInstitutions() public async Task Get_WhenCalledByUser_ItShouldReturn200WithListOfInstitutions()
{ {
var (user, institution) = await ExecuteAsync(static async (context, ct, sp) => var (user, institution) = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -32,7 +32,7 @@ public class LinkTests(TestApi testApi) : IntegrationTest(testApi)
[Fact] [Fact]
public async Task Link_WhenCalledWithUserWhoExists_ItShouldReturnLinkToken() public async Task Link_WhenCalledWithUserWhoExists_ItShouldReturnLinkToken()
{ {
var user = await ExecuteAsync(static async (context, ct, sp) => var user = await Api.ExecuteAsync(static async (context, ct, sp) =>
{ {
var passwordHasher = sp.GetRequiredService<IPasswordHasher>(); var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
var encryptor = sp.GetRequiredService<IEncryptor>(); var encryptor = sp.GetRequiredService<IEncryptor>();
@@ -2,51 +2,17 @@ namespace FiscalOS.API.Tests.Integration;
public abstract class IntegrationTest(TestApi testApi) : IClassFixture<TestApi>, IAsyncLifetime public abstract class IntegrationTest(TestApi testApi) : IClassFixture<TestApi>, IAsyncLifetime
{ {
public HttpClient Client => testApi.CreateClient(); protected TestApi Api => testApi;
protected HttpClient Client => testApi.CreateClient();
public async ValueTask InitializeAsync() public async ValueTask InitializeAsync()
{ {
await ExecuteAsync(static async (context, ct) => await Api.EnsureDbCreatedAsync();
{
await context.Database.EnsureCreatedAsync(ct);
}, TestContext.Current.CancellationToken);
}
protected async Task ExecuteAsync(Func<DbContext, CancellationToken, Task> action, CancellationToken ct)
{
await using var scope = testApi.Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await action(context, ct);
}
protected async Task ExecuteAsync(Func<DbContext, CancellationToken, IServiceProvider, Task> action, CancellationToken ct)
{
await using var scope = testApi.Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await action(context, ct, scope.ServiceProvider);
}
protected async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, Task<T>> action, CancellationToken ct)
{
await using var scope = testApi.Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return await action(context, ct);
}
protected async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, IServiceProvider, Task<T>> action, CancellationToken ct)
{
await using var scope = testApi.Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return await action(context, ct, scope.ServiceProvider);
} }
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
await ExecuteAsync(static async (context, ct) => await Api.EnsureDbDeletedAsync();
{
await context.Database.EnsureDeletedAsync(ct);
}, TestContext.Current.CancellationToken);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
} }
@@ -2,12 +2,4 @@ namespace FiscalOS.Infra.Tests.Unit;
public class PlaidTransactionSyncerTests public class PlaidTransactionSyncerTests
{ {
private readonly Mock<ILogger<PlaidTransactionSyncer>> _mockSyncer = new();
private
private readonly PlaidTransactionSyncer _sut;
public PlaidTransactionSyncer()
{
_sut = PlaidTransactionSyncer.From();
}
} }