diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 685b4c9..3fdc4f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,6 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: | - 3.1.x 6.0.x 7.0.x 8.0.x diff --git a/CHANGELOG.md b/CHANGELOG.md index f5db89b..183d6e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Represents the **NuGet** versions. +## v5.2.0 +- *Enhancement:* Added `TesterBase.UseAdditionalConfiguration` method to enable additional configuration to be specified that overrides the `IHostBuilder` as the host is being built. This leverages the underlying `IConfigurationBuilder.AddInMemoryCollection` capability to add. This is intended to support additional configuration that is not part of the standard `appsettings.json` or `appsettings.unittest.json` configuration. + ## v5.1.0 - *Enhancement:* Where an `HttpRequest` is used for an Azure Functions `HttpTriggerTester` the passed `HttpRequest.PathAndQuery` is checked against that defined by the corresponding `HttpTriggerAttribute.Route` and will result in an error where different. The `HttpTrigger.WithRouteChecK` and `WithNoRouteCheck` methods control the path and query checking as needed. diff --git a/Common.targets b/Common.targets index 06e2ecd..c5427f3 100644 --- a/Common.targets +++ b/Common.targets @@ -1,6 +1,6 @@  - 5.1.0 + 5.2.0 preview Avanade Avanade diff --git a/src/UnitTestEx.Azure.Functions/Azure/Functions/FunctionTesterBase.cs b/src/UnitTestEx.Azure.Functions/Azure/Functions/FunctionTesterBase.cs index 38094ed..7982b64 100644 --- a/src/UnitTestEx.Azure.Functions/Azure/Functions/FunctionTesterBase.cs +++ b/src/UnitTestEx.Azure.Functions/Azure/Functions/FunctionTesterBase.cs @@ -36,7 +36,6 @@ public abstract class FunctionTesterBase : TesterBase private readonly bool? _includeUnitTestConfiguration; private readonly bool? _includeUserSecrets; - private readonly IEnumerable>? _additionalConfiguration; private IHost? _host; private bool _disposed; @@ -62,7 +61,7 @@ public FunctionTesterBase(TestFrameworkImplementor implementor, bool? includeUni Logger = LoggerProvider.CreateLogger(GetType().Name); _includeUnitTestConfiguration = includeUnitTestConfiguration; _includeUserSecrets = includeUserSecrets; - _additionalConfiguration = additionalConfiguration; + AdditionalConfiguration = additionalConfiguration; } /// @@ -168,8 +167,8 @@ private IHost GetHost() if (!_includeUnitTestConfiguration.HasValue && TestSetUp.FunctionTesterIncludeUnitTestConfiguration || _includeUnitTestConfiguration.HasValue && _includeUnitTestConfiguration.Value) cb.AddJsonFile("appsettings.unittest.json", optional: true); - if (_additionalConfiguration != null) - cb.AddInMemoryCollection(_additionalConfiguration); + if (AdditionalConfiguration != null) + cb.AddInMemoryCollection(AdditionalConfiguration); }) .ConfigureServices(sc => { diff --git a/src/UnitTestEx.Azure.Functions/UnitTestEx.Azure.Functions.csproj b/src/UnitTestEx.Azure.Functions/UnitTestEx.Azure.Functions.csproj index aa2c9db..7ec8186 100644 --- a/src/UnitTestEx.Azure.Functions/UnitTestEx.Azure.Functions.csproj +++ b/src/UnitTestEx.Azure.Functions/UnitTestEx.Azure.Functions.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0;net9.0 UnitTestEx UnitTestEx UnitTestEx Azure Functions Test Extensions. diff --git a/src/UnitTestEx.Azure.ServiceBus/UnitTestEx.Azure.ServiceBus.csproj b/src/UnitTestEx.Azure.ServiceBus/UnitTestEx.Azure.ServiceBus.csproj index 3abfac6..9dbe5a4 100644 --- a/src/UnitTestEx.Azure.ServiceBus/UnitTestEx.Azure.ServiceBus.csproj +++ b/src/UnitTestEx.Azure.ServiceBus/UnitTestEx.Azure.ServiceBus.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0;net9.0 UnitTestEx UnitTestEx UnitTestEx Azure Functions Test Extensions. diff --git a/src/UnitTestEx.MSTest/UnitTestEx.MSTest.csproj b/src/UnitTestEx.MSTest/UnitTestEx.MSTest.csproj index 6b94c87..1dccf50 100644 --- a/src/UnitTestEx.MSTest/UnitTestEx.MSTest.csproj +++ b/src/UnitTestEx.MSTest/UnitTestEx.MSTest.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0;net9.0 UnitTestEx.MSTest UnitTestEx MSTest UnitTestEx MSTest Test Extensions. diff --git a/src/UnitTestEx.NUnit/UnitTestEx.NUnit.csproj b/src/UnitTestEx.NUnit/UnitTestEx.NUnit.csproj index f16c8e2..3406a36 100644 --- a/src/UnitTestEx.NUnit/UnitTestEx.NUnit.csproj +++ b/src/UnitTestEx.NUnit/UnitTestEx.NUnit.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0;net9.0 UnitTestEx.NUnit UnitTestEx NUnit UnitTestEx NUnit Test Extensions. diff --git a/src/UnitTestEx.Xunit/UnitTestEx.Xunit.csproj b/src/UnitTestEx.Xunit/UnitTestEx.Xunit.csproj index 5e88ecf..e8b0bb7 100644 --- a/src/UnitTestEx.Xunit/UnitTestEx.Xunit.csproj +++ b/src/UnitTestEx.Xunit/UnitTestEx.Xunit.csproj @@ -1,7 +1,7 @@  - net6.0;net7.0;net8.0 + net6.0;net7.0;net8.0;net9.0 UnitTestEx.Xunit UnitTestEx Xunit UnitTestEx Xunit Test Extensions. diff --git a/src/UnitTestEx/Abstractions/TesterBase.cs b/src/UnitTestEx/Abstractions/TesterBase.cs index 62f1144..de959c4 100644 --- a/src/UnitTestEx/Abstractions/TesterBase.cs +++ b/src/UnitTestEx/Abstractions/TesterBase.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using UnitTestEx.Json; using UnitTestEx.Logging; @@ -18,6 +19,7 @@ public abstract class TesterBase { private string? _userName; private readonly List> _configureServices = []; + private IEnumerable>? _additionalConfiguration; /// /// Static constructor. @@ -97,6 +99,19 @@ public string UserName protected set => _userName = value; } + /// + /// Gets the additional configuration used at host initialization (see ). + /// + public IEnumerable>? AdditionalConfiguration + { + get => _additionalConfiguration?.ToArray(); + protected set + { + _additionalConfiguration = value; + ResetHost(false); + } + } + /// /// Gets the from the underlying host. /// @@ -182,7 +197,7 @@ public void ConfigureServices(Action configureServices, bool protected void AddConfiguredServices(IServiceCollection services) { if (IsHostInstantiated) - throw new InvalidOperationException($"Underlying host has been instantiated and as such the {nameof(ConfigureServices)} operations can no longer be used."); + throw new InvalidOperationException($"Underlying host has been instantiated and as such the {nameof(ConfigureServices)} operations can no longer be used; consider using '{nameof(ResetHost)}' prior to enable."); foreach (var configureService in _configureServices) { diff --git a/src/UnitTestEx/Abstractions/TesterBaseT.cs b/src/UnitTestEx/Abstractions/TesterBaseT.cs index dc72f07..d75edfa 100644 --- a/src/UnitTestEx/Abstractions/TesterBaseT.cs +++ b/src/UnitTestEx/Abstractions/TesterBaseT.cs @@ -1,8 +1,10 @@ // Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/UnitTestEx +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using System; +using System.Collections.Generic; using UnitTestEx.Json; namespace UnitTestEx.Abstractions @@ -90,6 +92,27 @@ public TSelf UseJsonComparerOptions(JsonElementComparerOptions options) return (TSelf)this; } + /// + /// Updates (replaces) the (see ). + /// + /// The additional configuration key/value pairs. + /// The to support fluent-style method-chaining. + /// Usage will result in a . + public TSelf UseAdditionalConfiguration(IEnumerable>? additionalConfiguration) + { + AdditionalConfiguration = additionalConfiguration; + return (TSelf)this; + } + + /// + /// Updates (replaces) the (see ) with specified and . + /// + /// The additional configuration key. + /// The additional configuration value. + /// The to support fluent-style method-chaining. + /// Usage will result in a . + public TSelf UseAdditionalConfiguration(string key, string? value) => UseAdditionalConfiguration([new KeyValuePair(key, value)]); + /// /// Resets the underlying host to instantiate a new instance. /// diff --git a/src/UnitTestEx/AspNetCore/ApiTesterBase.cs b/src/UnitTestEx/AspNetCore/ApiTesterBase.cs index 6305379..8af53aa 100644 --- a/src/UnitTestEx/AspNetCore/ApiTesterBase.cs +++ b/src/UnitTestEx/AspNetCore/ApiTesterBase.cs @@ -61,7 +61,12 @@ protected WebApplicationFactory GetWebApplicationFactory() return _waf = new WebApplicationFactory().WithWebHostBuilder(whb => whb.UseSolutionRelativeContentRoot(Environment.CurrentDirectory) - .ConfigureAppConfiguration((_, x) => x.AddJsonFile("appsettings.unittest.json", optional: true)) + .ConfigureAppConfiguration((_, cb) => + { + cb.AddJsonFile("appsettings.unittest.json", optional: true); + if (AdditionalConfiguration != null) + cb.AddInMemoryCollection(AdditionalConfiguration); + }) .ConfigureServices(sc => { sc.AddHttpContextAccessor(); diff --git a/src/UnitTestEx/Generic/GenericTesterCore.cs b/src/UnitTestEx/Generic/GenericTesterCore.cs index 847068b..70a674d 100644 --- a/src/UnitTestEx/Generic/GenericTesterCore.cs +++ b/src/UnitTestEx/Generic/GenericTesterCore.cs @@ -67,6 +67,9 @@ private IHost GetHost() ep.ConfigureAppConfiguration(hbc, cb); cb.AddJsonFile("appsettings.unittest.json", optional: true) .AddEnvironmentVariables(); + + if (AdditionalConfiguration != null) + cb.AddInMemoryCollection(AdditionalConfiguration); }) .ConfigureServices(sc => { diff --git a/tests/UnitTestEx.NUnit.Test/Other/GenericTest.cs b/tests/UnitTestEx.NUnit.Test/Other/GenericTest.cs index e146ac8..500dbf5 100644 --- a/tests/UnitTestEx.NUnit.Test/Other/GenericTest.cs +++ b/tests/UnitTestEx.NUnit.Test/Other/GenericTest.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using System; using System.Threading.Tasks; @@ -51,6 +52,16 @@ public void Run_Service() test.Run(gin => gin.StirAsync()) .AssertException("As required by Bond; shaken, not stirred."); } + + [Test] + public void Configuration_Overrride_Use() + { + // Demonstrates how to override the configuration settings for a test. + using var test = GenericTester.Create(); + test.UseAdditionalConfiguration([new("SpecialKey", "NotSoSpecial")]); + var cv = test.Configuration.GetValue("SpecialKey"); + Assert.That(cv, Is.EqualTo("NotSoSpecial")); + } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Just for testing aye bro!")] diff --git a/tests/UnitTestEx.NUnit.Test/ProductControllerTest.cs b/tests/UnitTestEx.NUnit.Test/ProductControllerTest.cs index 93d9abc..621a8b5 100644 --- a/tests/UnitTestEx.NUnit.Test/ProductControllerTest.cs +++ b/tests/UnitTestEx.NUnit.Test/ProductControllerTest.cs @@ -101,6 +101,21 @@ public void Configuration() Assert.That(cv, Is.EqualTo("OtherValue")); } + [Test] + public void Configuration_Use() + { + using var test = ApiTester.Create(); + test.UseAdditionalConfiguration("SpecialKey", "NotSoSpecial"); + + var cv = test.Configuration.GetValue("SpecialKey"); + Assert.That(cv, Is.EqualTo("NotSoSpecial")); + + // Null to reset. + test.UseAdditionalConfiguration(null); + cv = test.Configuration.GetValue("SpecialKey"); + Assert.That(cv, Is.EqualTo("VerySpecialValue")); + } + [Test] public void DefaultHttpClient() { diff --git a/tests/UnitTestEx.NUnit.Test/ServiceBusFunctionTest.cs b/tests/UnitTestEx.NUnit.Test/ServiceBusFunctionTest.cs index 4252ab5..e84337f 100644 --- a/tests/UnitTestEx.NUnit.Test/ServiceBusFunctionTest.cs +++ b/tests/UnitTestEx.NUnit.Test/ServiceBusFunctionTest.cs @@ -151,5 +151,15 @@ public void Configuration_Overrride() var cv = test.Configuration.GetValue("SpecialKey"); Assert.That(cv, Is.EqualTo("NotSoSpecial")); } + + [Test] + public void Configuration_Overrride_Use() + { + // Demonstrates how to override the configuration settings for a test. + using var test = FunctionTester.Create(); + test.UseAdditionalConfiguration([new("SpecialKey", "NotSoSpecial")]); + var cv = test.Configuration.GetValue("SpecialKey"); + Assert.That(cv, Is.EqualTo("NotSoSpecial")); + } } } \ No newline at end of file