diff --git a/Directory.Build.props b/Directory.Build.props index 584b8fd..6838f67 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,8 +24,8 @@ https://github.com/managedcode/IntegrationTestBaseKit https://github.com/managedcode/IntegrationTestBaseKit Managed Code - IntegrationTestBaseKit - 0.0.1 - 0.0.1 + 0.0.2 + 0.0.2 diff --git a/ManagedCode.IntegrationTestBaseKit.Tests/HealthTests.cs b/ManagedCode.IntegrationTestBaseKit.Tests/HealthTests.cs index 2b41895..d0318dc 100644 --- a/ManagedCode.IntegrationTestBaseKit.Tests/HealthTests.cs +++ b/ManagedCode.IntegrationTestBaseKit.Tests/HealthTests.cs @@ -1,4 +1,7 @@ using FluentAssertions; +using TestBlazorApp; +using Testcontainers.Azurite; +using Testcontainers.PostgreSql; using Xunit.Abstractions; namespace ManagedCode.IntegrationTestBaseKit.Tests; @@ -23,4 +26,18 @@ public async Task BrowserHealthTest() .Should() .BeTrue(); } + + [Fact] + public void ConnectionStringTest() + { + StaticContainer.AzureBlobConnectionString + .Should() + .Be(testApplication.GetContainer() + .GetConnectionString()); + + StaticContainer.PostgreSqlConnectionString + .Should() + .Be(testApplication.GetContainer("postgree") + .GetConnectionString()); + } } \ No newline at end of file diff --git a/ManagedCode.IntegrationTestBaseKit.Tests/TestApp.cs b/ManagedCode.IntegrationTestBaseKit.Tests/TestApp.cs index 3f1eaea..0a33fa9 100644 --- a/ManagedCode.IntegrationTestBaseKit.Tests/TestApp.cs +++ b/ManagedCode.IntegrationTestBaseKit.Tests/TestApp.cs @@ -13,4 +13,12 @@ protected override async Task ConfigureTestContainers() AddContainer(new AzuriteBuilder().Build()); AddContainer("postgree", new PostgreSqlBuilder().Build()); } + + protected override void ConfigureConfiguration() + { + SetConfigurationValue("AzureBlob", GetContainer() + .GetConnectionString()); + SetConfigurationValue("ConnectionStrings:PostgreSql", GetContainer("postgree") + .GetConnectionString()); + } } \ No newline at end of file diff --git a/ManagedCode.IntegrationTestBaseKit.XUnit/BaseXUnitTestApp.cs b/ManagedCode.IntegrationTestBaseKit.XUnit/BaseXUnitTestApp.cs index b6d8c87..b0937c7 100644 --- a/ManagedCode.IntegrationTestBaseKit.XUnit/BaseXUnitTestApp.cs +++ b/ManagedCode.IntegrationTestBaseKit.XUnit/BaseXUnitTestApp.cs @@ -2,11 +2,16 @@ namespace ManagedCode.IntegrationTestBaseKit.XUnit; -public abstract class BaseXUnitTestApp : BaseTestApp, IAsyncLifetime - where TEntryPoint : class +public abstract class BaseXUnitTestApp : BaseTestApp, IAsyncLifetime where TEntryPoint : class { + async Task IAsyncLifetime.InitializeAsync() + { + await InitializeAsync(); + CreateHttpClient(); + } + async Task IAsyncLifetime.DisposeAsync() { - await base.DisposeAsync(); + await DisposeAsync(); } } \ No newline at end of file diff --git a/ManagedCode.IntegrationTestBaseKit/BaseTestApp.cs b/ManagedCode.IntegrationTestBaseKit/BaseTestApp.cs index a59442c..d851774 100644 --- a/ManagedCode.IntegrationTestBaseKit/BaseTestApp.cs +++ b/ManagedCode.IntegrationTestBaseKit/BaseTestApp.cs @@ -5,17 +5,20 @@ using Microsoft.AspNetCore.Http.Connections.Client; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.SignalR.Client; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Playwright; namespace ManagedCode.IntegrationTestBaseKit; -public abstract class BaseTestApp : WebApplicationFactory - where TEntryPoint : class +public abstract class BaseTestApp : WebApplicationFactory where TEntryPoint : class { private IHost? _host; + private readonly ConfigurationBuilder ConfigurationBuilder = new(); + + protected virtual bool UsePlaywright { get; } = true; private PlaywrightWrapper Fixture { get; } = new(); protected Dictionary Containers { get; } = new(); @@ -62,18 +65,44 @@ public T GetContainer() where T : DockerContainer public virtual async Task InitializeAsync() { await ConfigureTestContainers(); - await Fixture.InitializeAsync(); + + if (UsePlaywright) + await Fixture.InitializeAsync(); + foreach (var container in Containers) await container.Value.StartAsync(); } protected override IHost CreateHost(IHostBuilder builder) { + ConfigureConfiguration(); + var configuration = ConfigurationBuilder.Build(); + builder.ConfigureWebHost(hostBuilder => + { + foreach (var setting in configuration.AsEnumerable(true)) + hostBuilder.UseSetting(setting.Key, setting.Value); + }); + + // Create the host for TestServer now before we + // modify the builder to use Kestrel instead. var testHost = builder.Build(); + + // Modify the host builder to use Kestrel instead + // of TestServer so we can listen on a real address. builder.ConfigureWebHost(hostBuilder => hostBuilder.UseKestrel()); - _host = builder.Build(); + + // Create and start the Kestrel server before the test server, + // otherwise due to the way the deferred host builder works + // for minimal hosting, the server will not get "initialized + // enough" for the address it is listening on to be available. + // See https://github.com/dotnet/aspnetcore/issues/33846. + _host = builder.Build(); //base.CreateHost(builder); _host.Start(); + // Extract the selected dynamic port out of the Kestrel server + // and assign it onto the client options for convenience so it + // "just works" as otherwise it'll be the default http://localhost + // URL, which won't route to the Kestrel-hosted HTTP server. var server = _host.Services.GetRequiredService(); var addressFeature = server.Features.Get(); ClientOptions.BaseAddress = addressFeature!.Addresses @@ -84,13 +113,9 @@ protected override IHost CreateHost(IHostBuilder builder) return testHost; } - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - builder.UseEnvironment("Development"); - } - public override async ValueTask DisposeAsync() { + _host?.Dispose(); await Fixture.DisposeAsync(); foreach (var container in Containers) { @@ -125,6 +150,9 @@ public HubConnection CreateSignalRClient(string hubUrl, Action OpenNewPage(string url) { + if (!UsePlaywright) + throw new InvalidOperationException("Playwright is not enabled"); + var fullUrl = new Uri(ServerUri, url).ToString(); var context = await Browser.NewContextAsync(); var page = await context.NewPageAsync(); @@ -144,4 +172,10 @@ protected void AddContainer(DockerContainer container) } protected abstract Task ConfigureTestContainers(); + protected abstract void ConfigureConfiguration(); + + protected void SetConfigurationValue(string key, string value) + { + ConfigurationBuilder.AddInMemoryCollection(new Dictionary { { key, value } }!); + } } \ No newline at end of file diff --git a/README.md b/README.md index 75758ac..47d20d1 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ dotnet add package ManagedCode.IntegrationTestBaseKit ``` for xUnit integration use the following command: + ```sh dotnet add package ManagedCode.ManagedCode.IntegrationTestBaseKit.XUnit ``` diff --git a/TestBlazorApp/Program.cs b/TestBlazorApp/Program.cs index baa38c1..b542d3c 100644 --- a/TestBlazorApp/Program.cs +++ b/TestBlazorApp/Program.cs @@ -21,6 +21,11 @@ public static void Main(string[] args) .AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + StaticContainer.PostgreSqlConnectionString = builder.Configuration.GetConnectionString("PostgreSql"); + StaticContainer.AzureBlobConnectionString = builder.Configuration.GetValue("AzureBlob"); + + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/TestBlazorApp/StaticContainer.cs b/TestBlazorApp/StaticContainer.cs new file mode 100644 index 0000000..ba9f037 --- /dev/null +++ b/TestBlazorApp/StaticContainer.cs @@ -0,0 +1,7 @@ +namespace TestBlazorApp; + +public static class StaticContainer +{ + public static string PostgreSqlConnectionString; + public static string AzureBlobConnectionString; +} \ No newline at end of file