Skip to content

Commit 83beb7c

Browse files
authored
fix: disposal for test to avoid connection and memory leaks in tests
1 parent 229dd3c commit 83beb7c

9 files changed

Lines changed: 71 additions & 28 deletions

File tree

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Common/Events/EventBus/InMemory/InMemoryEventBusTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ internal async Task Given_valid_event_published_Then_event_should_be_consumed()
2727

2828
private IEventBus GetEventBus() =>
2929
_applicationInMemory.Services
30-
.CreateScope()
30+
.CreateScope()!
3131
.ServiceProvider
3232
.GetRequiredService<IEventBus>();
3333
}

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Contracts/PrepareContract/PrepareContractTests.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace EvolutionaryArchitecture.Fitnet.IntegrationTests.Contracts.PrepareCont
1111
public sealed class PrepareContractTests(
1212
WebApplicationFactory<Program> applicationInMemoryFactory,
1313
DatabaseContainer database) : IClassFixture<WebApplicationFactory<Program>>,
14-
IClassFixture<DatabaseContainer>
14+
IClassFixture<DatabaseContainer>, IAsyncLifetime
1515
{
1616
private readonly HttpClient _applicationHttpClient = applicationInMemoryFactory
1717
.WithContainerDatabaseConfigured(database.ConnectionString!)
@@ -24,7 +24,7 @@ internal async Task Given_valid_contract_preparation_request_Then_should_return_
2424
var requestParameters = PrepareContractRequestParameters.GetValid();
2525

2626
// Act
27-
var prepareContractResponse = await PrepareCorrectContract(requestParameters);
27+
using var prepareContractResponse = await PrepareCorrectContract(requestParameters);
2828

2929
// Assert
3030
prepareContractResponse.StatusCode.ShouldBe(HttpStatusCode.Created);
@@ -61,7 +61,7 @@ internal async Task Given_contract_preparation_request_with_invalid_age_Then_sho
6161
requestParameters.MaxAge, requestParameters.MinHeight, requestParameters.MaxHeight);
6262

6363
// Act
64-
var prepareContractResponse =
64+
using var prepareContractResponse =
6565
await _applicationHttpClient.PostAsJsonAsync(ContractsApiPaths.Prepare, prepareContractRequest);
6666

6767
// Assert
@@ -82,7 +82,7 @@ internal async Task Given_contract_preparation_request_with_invalid_height_Then_
8282
requestParameters.MaxAge, requestParameters.MinHeight, requestParameters.MaxHeight);
8383

8484
// Act
85-
var prepareContractResponse =
85+
using var prepareContractResponse =
8686
await _applicationHttpClient.PostAsJsonAsync(ContractsApiPaths.Prepare, prepareContractRequest);
8787

8888
// Assert
@@ -103,7 +103,7 @@ internal async Task
103103
await PrepareCorrectContract(requestParameters, customerId);
104104

105105
//Act
106-
var prepareContractResponse = await PrepareCorrectContract(requestParameters, customerId);
106+
using var prepareContractResponse = await PrepareCorrectContract(requestParameters, customerId);
107107

108108
// Assert
109109
prepareContractResponse.StatusCode.ShouldBe(HttpStatusCode.Conflict);
@@ -122,4 +122,12 @@ private async Task<HttpResponseMessage> PrepareCorrectContract(PrepareContractRe
122122

123123
return prepareContractResponse;
124124
}
125+
126+
public Task InitializeAsync() => Task.CompletedTask;
127+
128+
public async Task DisposeAsync()
129+
{
130+
_applicationHttpClient.Dispose();
131+
await applicationInMemoryFactory.DisposeAsync();
132+
}
125133
}

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Contracts/SignContract/SignContractTests.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,29 @@ namespace EvolutionaryArchitecture.Fitnet.IntegrationTests.Contracts.SignContrac
99
using EvolutionaryArchitecture.Fitnet.Common.Events.EventBus;
1010
using Microsoft.AspNetCore.Mvc;
1111

12-
public sealed class SignContractTests : IClassFixture<WebApplicationFactory<Program>>, IClassFixture<DatabaseContainer>
12+
public sealed class SignContractTests : IClassFixture<WebApplicationFactory<Program>>, IClassFixture<DatabaseContainer>, IAsyncLifetime
1313
{
1414
private readonly HttpClient _applicationHttpClient;
1515
private readonly IEventBus _fakeEventBus = Substitute.For<IEventBus>();
16+
private readonly WebApplicationFactory<Program> _applicationInMemoryFactory;
1617

1718
public SignContractTests(WebApplicationFactory<Program> applicationInMemoryFactory,
18-
DatabaseContainer database) =>
19+
DatabaseContainer database)
20+
{
21+
_applicationInMemoryFactory = applicationInMemoryFactory;
1922
_applicationHttpClient = applicationInMemoryFactory
2023
.WithFakeEventBus(_fakeEventBus)
2124
.WithContainerDatabaseConfigured(database.ConnectionString!)
2225
.CreateClient();
26+
}
27+
28+
public Task InitializeAsync() => Task.CompletedTask;
29+
30+
public async Task DisposeAsync()
31+
{
32+
_applicationHttpClient.Dispose();
33+
await _applicationInMemoryFactory.DisposeAsync();
34+
}
2335

2436
[Fact]
2537
internal async Task Given_valid_contract_signature_request_Then_should_return_no_content_status_code()
@@ -30,7 +42,7 @@ internal async Task Given_valid_contract_signature_request_Then_should_return_no
3042
var signContractRequest = new SignContractRequest(requestParameters.SignedAt);
3143

3244
// Act
33-
var signContractResponse =
45+
using var signContractResponse =
3446
await _applicationHttpClient.PatchAsJsonAsync(requestParameters.Url, signContractRequest);
3547

3648
// Assert
@@ -63,7 +75,7 @@ internal async Task Given_contract_signature_request_with_not_existing_id_Then_s
6375
var signContractRequest = new SignContractRequest(requestParameters.SignedAt);
6476

6577
// Act
66-
var signContractResponse =
78+
using var signContractResponse =
6779
await _applicationHttpClient.PatchAsJsonAsync(requestParameters.Url, signContractRequest);
6880

6981
// Assert
@@ -81,7 +93,7 @@ internal async Task
8193
var signContractRequest = new SignContractRequest(requestParameters.SignedAt);
8294

8395
// Act
84-
var signContractResponse =
96+
using var signContractResponse =
8597
await _applicationHttpClient.PatchAsJsonAsync(requestParameters.Url, signContractRequest);
8698

8799
// Assert
@@ -97,7 +109,7 @@ private async Task<Guid> PrepareContract()
97109
var requestParameters = PrepareContractRequestParameters.GetValid();
98110
PrepareContractRequest prepareContractRequest = new PrepareContractRequestFaker(requestParameters.MinAge,
99111
requestParameters.MaxAge, requestParameters.MinHeight, requestParameters.MaxHeight);
100-
var prepareContractResponse =
112+
using var prepareContractResponse =
101113
await _applicationHttpClient.PostAsJsonAsync(ContractsApiPaths.Prepare, prepareContractRequest);
102114
var preparedContractId = await prepareContractResponse.Content.ReadFromJsonAsync<Guid>();
103115

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Offers/Prepare/PrepareOfferTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public PrepareOfferTests(WebApplicationFactory<Program> applicationInMemoryFacto
1919
_applicationInMemory = applicationInMemoryFactory
2020
.WithFakeEventBus(_fakeEventBus)
2121
.WithContainerDatabaseConfigured(database.ConnectionString!);
22-
2322
_applicationInMemory.CreateClient();
2423
}
2524

@@ -41,4 +40,4 @@ internal async Task Given_pass_expired_event_published_Then_new_offer_should_be_
4140

4241
private void EnsureThatOfferPreparedEventWasPublished() => _fakeEventBus.Received(1)
4342
.PublishAsync(Arg.Any<OfferPrepareEvent>(), Arg.Any<CancellationToken>());
44-
}
43+
}

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Passes/MarkPassAsExpired/MarkPassAsExpiredTests.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace EvolutionaryArchitecture.Fitnet.IntegrationTests.Passes.MarkPassAsExpi
1010
using Fitnet.Passes.MarkPassAsExpired.Events;
1111

1212
public sealed class MarkPassAsExpiredTests : IClassFixture<WebApplicationFactory<Program>>,
13-
IClassFixture<DatabaseContainer>
13+
IClassFixture<DatabaseContainer>, IAsyncLifetime
1414
{
1515
private static readonly StringContent EmptyContent = new(string.Empty);
1616

@@ -51,7 +51,7 @@ internal async Task Given_valid_mark_pass_as_expired_request_Then_should_publish
5151
var url = BuildUrl(registeredPassId);
5252

5353
// Act
54-
var markAsExpiredResponse = await _applicationHttpClient.PatchAsJsonAsync(url, EmptyContent);
54+
using var markAsExpiredResponse = await _applicationHttpClient.PatchAsJsonAsync(url, EmptyContent);
5555

5656
// Assert
5757
markAsExpiredResponse.StatusCode.ShouldBe(HttpStatusCode.NoContent);
@@ -65,7 +65,7 @@ internal async Task Given_mark_pass_as_expired_request_with_not_existing_id_Then
6565
var url = BuildUrl(notExistingId);
6666

6767
// Act
68-
var markAsExpiredResponse = await _applicationHttpClient.PatchAsJsonAsync(url, EmptyContent);
68+
using var markAsExpiredResponse = await _applicationHttpClient.PatchAsJsonAsync(url, EmptyContent);
6969

7070
// Assert
7171
markAsExpiredResponse.StatusCode.ShouldBe(HttpStatusCode.NotFound);
@@ -91,14 +91,23 @@ private async Task<Guid> GetCreatedPass(Guid customerId)
9191

9292
private async Task<PassDto?> CreatedPass(Guid customerId)
9393
{
94-
var getAllPassesResponse = await _applicationHttpClient.GetAsync(PassesApiPaths.GetAll);
94+
using var getAllPassesResponse = await _applicationHttpClient.GetAsync(PassesApiPaths.GetAll);
9595
var response = await getAllPassesResponse.Content.ReadFromJsonAsync<GetAllPassesResponse>();
9696
var createdPass = response!.Passes.FirstOrDefault(pass => pass.CustomerId == customerId);
97+
9798
return createdPass;
9899
}
99100

100101
private static string BuildUrl(Guid id) => PassesApiPaths.MarkPassAsExpired.Replace("{id}", id.ToString());
101102

102103
private void EnsureThatPassExpiredEventWasPublished() => _fakeEventBus.Received(1)
103104
.PublishAsync(Arg.Any<PassExpiredEvent>(), Arg.Any<CancellationToken>());
105+
106+
public Task InitializeAsync() => Task.CompletedTask;
107+
108+
public async Task DisposeAsync()
109+
{
110+
_applicationHttpClient.Dispose();
111+
await _applicationInMemoryFactory.DisposeAsync();
112+
}
104113
}

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Passes/RegisterPass/RegisterPassTests.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,27 @@ namespace EvolutionaryArchitecture.Fitnet.IntegrationTests.Passes.RegisterPass;
66
using Fitnet.Passes.RegisterPass.Events;
77
using EvolutionaryArchitecture.Fitnet.Common.Events.EventBus;
88

9-
public sealed class RegisterPassTests : IClassFixture<WebApplicationFactory<Program>>,
10-
IClassFixture<DatabaseContainer>
9+
public sealed class RegisterPassTests : IClassFixture<WebApplicationFactory<Program>>, IClassFixture<DatabaseContainer>, IAsyncLifetime
1110
{
1211
private readonly WebApplicationFactory<Program> _applicationInMemory;
1312
private readonly IEventBus _fakeEventBus = Substitute.For<IEventBus>();
13+
private readonly HttpClient _applicationHttpClient;
1414

1515
public RegisterPassTests(WebApplicationFactory<Program> applicationInMemoryFactory,
1616
DatabaseContainer database)
1717
{
1818
_applicationInMemory = applicationInMemoryFactory
19-
.WithContainerDatabaseConfigured(database.ConnectionString!)
20-
.WithFakeEventBus(_fakeEventBus);
21-
_applicationInMemory.CreateClient();
19+
.WithContainerDatabaseConfigured(database.ConnectionString!)
20+
.WithFakeEventBus(_fakeEventBus);
21+
_applicationHttpClient = _applicationInMemory.CreateClient();
22+
}
23+
24+
public Task InitializeAsync() => Task.CompletedTask;
25+
26+
public async Task DisposeAsync()
27+
{
28+
_applicationHttpClient.Dispose();
29+
await _applicationInMemory.DisposeAsync();
2230
}
2331

2432
[Fact]

Chapter-1-initial-architecture/Src/Fitnet.IntegrationTests/Reports/GenerateNewPassesPerMonthReport/GenerateNewPassesPerMonthReportTests.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace EvolutionaryArchitecture.Fitnet.IntegrationTests.Reports.GenerateNewPassesPerMonthReport;
22

3+
using System;
34
using Common.TestEngine.Configuration;
45
using Common.TestEngine.IntegrationEvents.Handlers;
56
using Common.TestEngine.Time;
@@ -9,7 +10,7 @@ namespace EvolutionaryArchitecture.Fitnet.IntegrationTests.Reports.GenerateNewPa
910
using Passes.RegisterPass;
1011
using TestData;
1112

12-
public sealed class GenerateNewPassesPerMonthReportTests : IClassFixture<WebApplicationFactory<Program>>, IClassFixture<DatabaseContainer>
13+
public sealed class GenerateNewPassesPerMonthReportTests : IClassFixture<WebApplicationFactory<Program>>, IClassFixture<DatabaseContainer>, IAsyncLifetime
1314
{
1415
private static readonly FakeTimeProvider FakeTimeProvider = new(ReportTestCases.FakeNowDate);
1516
private readonly HttpClient _applicationHttpClient;
@@ -21,7 +22,6 @@ public GenerateNewPassesPerMonthReportTests(WebApplicationFactory<Program> appli
2122
_applicationInMemoryFactory = applicationInMemoryFactory
2223
.WithContainerDatabaseConfigured(database.ConnectionString!)
2324
.WithTime(FakeTimeProvider);
24-
2525
_applicationHttpClient = _applicationInMemoryFactory.CreateClient();
2626
}
2727

@@ -34,7 +34,7 @@ internal async Task Given_valid_generate_new_report_request_Then_should_return_c
3434
await RegisterPasses(passRegistrationDateRanges);
3535

3636
// Act
37-
var getReportResult = await _applicationHttpClient.GetAsync(ReportsApiPaths.GenerateNewReport);
37+
using var getReportResult = await _applicationHttpClient.GetAsync(ReportsApiPaths.GenerateNewReport);
3838

3939
// Assert
4040
getReportResult.StatusCode.ShouldBe(HttpStatusCode.OK);
@@ -58,4 +58,12 @@ private async Task RegisterPass(DateTimeOffset from, DateTimeOffset to)
5858
var @event = ContractSignedEventFaker.Create(from, to);
5959
await integrationEventHandler.Handle(@event, CancellationToken.None);
6060
}
61+
62+
public Task InitializeAsync() => Task.CompletedTask;
63+
64+
public async Task DisposeAsync()
65+
{
66+
_applicationHttpClient.Dispose();
67+
await _applicationInMemoryFactory.DisposeAsync();
68+
}
6169
}

Chapter-1-initial-architecture/Src/Fitnet/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
builder.Services.AddOffers(builder.Configuration);
2424
builder.Services.AddReports();
2525

26-
var app = builder.Build();
26+
await using var app = builder.Build();
2727

2828
if (app.Environment.IsDevelopment())
2929
{

Chapter-1-initial-architecture/Src/Fitnet/Reports/DataAccess/DatabaseConnectionFactory.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ public IDbConnection Create()
1313
{
1414
return _connection;
1515
}
16-
1716
_connection =
1817
new NpgsqlConnection(configuration.GetConnectionString("Reports"));
1918
_connection.Open();

0 commit comments

Comments
 (0)