Skip to content

Commit d80ff29

Browse files
authored
v5.5.0 (#92)
* v5.5.0 - *Enhancement:* The `GenericTester` where using `.NET8.0` and above will leverage the new `IHostApplicationBuilder` versus existing `IHostBuilder` (see Microsoft [documentation](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host) and [recommendation](dotnet/runtime#81090 (comment))). Additionally, if a `TEntryPoint` is specified with a method signature of `public void ConfigureApplication(IHostApplicationBuilder builder)` then this will be automatically invoked during host instantiation. This is a non-breaking change as largely internal. * CI update. * .NET6/8 API * NET8 Xunit
1 parent 78724ce commit d80ff29

File tree

11 files changed

+139
-15
lines changed

11 files changed

+139
-15
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ jobs:
3636
3737
- name: Explicit NUnit test
3838
run: |
39-
cp tests/UnitTestEx.Api/bin/Debug/net6.0/UnitTestEx.Api.deps.json tests/UnitTestEx.NUnit.Test/bin/Debug/net6.0
40-
cd tests/UnitTestEx.NUnit.Test/bin/Debug/net6.0
39+
cp tests/UnitTestEx.Api/bin/Debug/net8.0/UnitTestEx.Api.deps.json tests/UnitTestEx.NUnit.Test/bin/Debug/net8.0
40+
cd tests/UnitTestEx.NUnit.Test/bin/Debug/net8.0
4141
dotnet test UnitTestEx.NUnit.Test.dll --no-build --verbosity normal
4242
4343
- name: Explicit Xunit test
4444
run: |
45-
cp tests/UnitTestEx.Api/bin/Debug/net6.0/UnitTestEx.Api.deps.json tests/UnitTestEx.Xunit.Test/bin/Debug/net6.0
46-
cd tests/UnitTestEx.Xunit.Test/bin/Debug/net6.0
45+
cp tests/UnitTestEx.Api/bin/Debug/net8.0/UnitTestEx.Api.deps.json tests/UnitTestEx.Xunit.Test/bin/Debug/net8.0
46+
cd tests/UnitTestEx.Xunit.Test/bin/Debug/net8.0
4747
dotnet test UnitTestEx.Xunit.Test.dll --no-build --verbosity normal --tests MockHttpClientTest
4848
dotnet test UnitTestEx.Xunit.Test.dll --no-build --verbosity normal --tests PersonFunctionTest
4949
dotnet test UnitTestEx.Xunit.Test.dll --no-build --verbosity normal --tests ProductFunctionTest

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Represents the **NuGet** versions.
44

5+
## v5.5.0
6+
- *Enhancement:* The `GenericTester` where using `.NET8.0` and above will leverage the new `IHostApplicationBuilder` versus existing `IHostBuilder` (see Microsoft [documentation](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host) and [recommendation](https://github.com/dotnet/runtime/discussions/81090#discussioncomment-4784551)). Additionally, if a `TEntryPoint` is specified with a method signature of `public void ConfigureApplication(IHostApplicationBuilder builder)` then this will be automatically invoked during host instantiation. This is a non-breaking change as largely internal.
7+
58
## v5.4.6
69
- *Fixed:* Added `TestFrameworkImplementor.SetLocalCreateFactory` to Xunit `ApiTestFixture` constructor to ensure set correctly for the `OnConfiguration` method override.
710

Common.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>5.4.6</Version>
3+
<Version>5.5.0</Version>
44
<LangVersion>preview</LangVersion>
55
<Authors>Avanade</Authors>
66
<Company>Avanade</Company>

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@ test.Run<Gin, int>(gin => gin.Pour())
113113
.AssertValue(1);
114114
```
115115

116+
Additionally, where the `TEntryPoint` is specified and implements `ConfigureApplication` (`.NET8.0` or above) this will be invoked automatically to perform any additional configuration.
117+
118+
``` csharp
119+
using var test = GenericTester.Create<Startup>();
120+
test.Run<Gin, int>(gin => gin.Pour())
121+
.AssertSuccess()
122+
.AssertValue(1);
123+
124+
public class Startup
125+
{
126+
public void ConfigureApplication(IHostApplicationBuilder builder) => builder.Services.AddSingleton<Gin>();
127+
}
128+
```
129+
116130
<br/>
117131

118132
## DI Mocking

src/UnitTestEx/Generic/GenericTesterCore.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.Extensions.Hosting;
66
using Microsoft.Extensions.Logging;
77
using System;
8+
using System.Reflection;
89
using UnitTestEx.Abstractions;
910
using UnitTestEx.Expectations;
1011
using UnitTestEx.Hosting;
@@ -58,7 +59,56 @@ private IHost GetHost()
5859

5960
var ep = new EntryPoint(Activator.CreateInstance<TEntryPoint>());
6061

61-
return _host ??= new HostBuilder()
62+
#if NET8_0_OR_GREATER
63+
var settings = new HostApplicationBuilderSettings
64+
{
65+
EnvironmentName = TestSetUp.Environment,
66+
ContentRootPath = Environment.CurrentDirectory
67+
};
68+
69+
var builder = Host.CreateApplicationBuilder(settings);
70+
builder.Logging.SetMinimumLevel(SetUp.MinimumLogLevel).ClearProviders().AddProvider(LoggerProvider);
71+
72+
if (ep.HasConfigureHostConfiguration)
73+
ep.ConfigureHostConfiguration(builder.Configuration);
74+
75+
builder.Configuration.AddJsonFile("appsettings.json", optional: true)
76+
.AddJsonFile($"appsettings.{TestSetUp.Environment.ToLowerInvariant()}.json", optional: true);
77+
78+
if (ep.HasConfigureAppConfiguration)
79+
{
80+
var fi = builder.GetType().GetField("_hostBuilderContext", BindingFlags.Instance | BindingFlags.NonPublic);
81+
if (fi is not null)
82+
{
83+
var hbc = (HostBuilderContext)fi.GetValue(builder)!;
84+
ep.ConfigureAppConfiguration(hbc, builder.Configuration);
85+
}
86+
}
87+
88+
builder.Configuration.AddJsonFile("appsettings.unittest.json", optional: true)
89+
.AddEnvironmentVariables();
90+
91+
if (AdditionalConfiguration != null)
92+
builder.Configuration.AddInMemoryCollection(AdditionalConfiguration);
93+
94+
if (ep.HasConfigureServices)
95+
ep.ConfigureServices(builder.Services);
96+
97+
if (ep.HasConfigureApplication)
98+
ep.ConfigureApplication(builder);
99+
100+
builder.Services.ReplaceScoped(_ => SharedState);
101+
102+
foreach (var tec in TestSetUp.Extensions)
103+
tec.ConfigureServices(this, builder.Services);
104+
105+
SetUp.ConfigureServices?.Invoke(builder.Services);
106+
AddConfiguredServices(builder.Services);
107+
108+
_host = builder.Build();
109+
return _host;
110+
#else
111+
return _host ??= Host.CreateDefaultBuilder()
62112
.UseEnvironment(TestSetUp.Environment)
63113
.ConfigureLogging((lb) => { lb.SetMinimumLevel(SetUp.MinimumLogLevel); lb.ClearProviders(); lb.AddProvider(LoggerProvider); })
64114
.ConfigureHostConfiguration(cb =>
@@ -88,6 +138,7 @@ private IHost GetHost()
88138
SetUp.ConfigureServices?.Invoke(sc);
89139
AddConfiguredServices(sc);
90140
}).Build();
141+
#endif
91142
}
92143
}
93144

src/UnitTestEx/Hosting/EntryPoint.cs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ public class EntryPoint
1818
private readonly MethodInfo? _mi1;
1919
private readonly MethodInfo? _mi2;
2020
private readonly MethodInfo? _mi3;
21+
#if NET8_0_OR_GREATER
22+
private readonly MethodInfo? _mi4;
23+
#endif
2124

2225
/// <summary>
2326
/// Initializes a new instance of the <see cref="EntryPoint"/> class.
@@ -29,28 +32,62 @@ public EntryPoint(object instance)
2932
_mi1 = instance.GetType().GetMethod(nameof(ConfigureAppConfiguration), BindingFlags.Instance | BindingFlags.Public, [typeof(HostBuilderContext), typeof(IConfigurationBuilder)]);
3033
_mi2 = instance.GetType().GetMethod(nameof(ConfigureHostConfiguration), BindingFlags.Instance | BindingFlags.Public, [typeof(IConfigurationBuilder)]);
3134
_mi3 = instance.GetType().GetMethod(nameof(ConfigureServices), BindingFlags.Instance | BindingFlags.Public, [typeof(IServiceCollection)]);
35+
_mi3 = instance.GetType().GetMethod(nameof(ConfigureServices), BindingFlags.Instance | BindingFlags.Public, [typeof(IServiceCollection)]);
36+
#if NET8_0_OR_GREATER
37+
_mi4 = instance.GetType().GetMethod(nameof(ConfigureApplication), BindingFlags.Instance | BindingFlags.Public, [typeof(IHostApplicationBuilder)]);
38+
#endif
3239
}
3340

41+
/// <summary>
42+
/// Indicates whether the <see cref="ConfigureAppConfiguration"/> has been defined on the entry point instance.
43+
/// </summary>
44+
public bool HasConfigureAppConfiguration => _mi1 is not null;
45+
46+
/// <summary>
47+
/// Indicates whether the <see cref="ConfigureHostConfiguration"/> has been defined on the entry point instance.
48+
/// </summary>
49+
public bool HasConfigureHostConfiguration => _mi2 is not null;
50+
51+
/// <summary>
52+
/// Indicates whether the <see cref="ConfigureServices"/> has been defined on the entry point instance.
53+
/// </summary>
54+
public bool HasConfigureServices => _mi3 is not null;
55+
56+
#if NET8_0_OR_GREATER
57+
/// <summary>
58+
/// Indicates whether the <see cref="ConfigureApplication"/> has been defined on the entry point instance.
59+
/// </summary>
60+
public bool HasConfigureApplication => _mi4 is not null;
61+
#endif
62+
3463
/// <summary>
3564
/// Sets up the configuration for the remainder of the build process and application.
3665
/// </summary>
3766
/// <param name="context"></param>
3867
/// <param name="config"></param>
3968
/// <remarks>This is intended to be invoked by the <see cref="IHostBuilder.ConfigureAppConfiguration(System.Action{HostBuilderContext, IConfigurationBuilder})"/>.</remarks>
40-
public void ConfigureAppConfiguration(HostBuilderContext context, IConfigurationBuilder config) => _mi1?.Invoke(_instance, new object[] { context, config });
69+
public void ConfigureAppConfiguration(HostBuilderContext context, IConfigurationBuilder config) => _mi1?.Invoke(_instance, [context, config]);
4170

4271
/// <summary>
4372
/// Sets up the configuration for the builder itself to initialize the <see cref="IHostEnvironment"/>.
4473
/// </summary>
4574
/// <param name="config">The <see cref="IConfigurationBuilder"/>.</param>
4675
/// <remarks>This is intended to be invoked by the <see cref="IHostBuilder.ConfigureHostConfiguration(System.Action{IConfigurationBuilder})"/>.</remarks>
47-
public void ConfigureHostConfiguration(IConfigurationBuilder config) => _mi2?.Invoke(_instance, new object[] { config });
76+
public void ConfigureHostConfiguration(IConfigurationBuilder config) => _mi2?.Invoke(_instance, [config]);
4877

4978
/// <summary>
5079
/// Adds services to the container.
5180
/// </summary>
5281
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
5382
/// <remarks>This is intended to be invoked by the <see cref="IHostBuilder.ConfigureServices(System.Action{HostBuilderContext, IServiceCollection})"/>.</remarks>
54-
public void ConfigureServices(IServiceCollection services) => _mi3?.Invoke(_instance, new object[] { services });
83+
public void ConfigureServices(IServiceCollection services) => _mi3?.Invoke(_instance, [services]);
84+
85+
#if NET8_0_OR_GREATER
86+
/// <summary>
87+
/// Enables further configuration of the <see cref="IHostApplicationBuilder"/> after it has been created/pre-configured.
88+
/// </summary>
89+
/// <param name="builder">The <see cref="IHostApplicationBuilder"/></param>
90+
public void ConfigureApplication(IHostApplicationBuilder builder) => _mi4?.Invoke(_instance, [builder]);
91+
#endif
5592
}
5693
}

tests/UnitTestEx.Api/Controllers/PersonController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public IActionResult Get(int id)
4444
[HttpGet("")]
4545
public IActionResult GetByArgs(string firstName, string lastName, [FromQuery] List<int> id = default)
4646
{
47-
return new ObjectResult($"{firstName}-{lastName}-{string.Join(",", id)}");
47+
return new ObjectResult($"{firstName}-{lastName}-{(id is null ? "" : string.Join(",", id))}");
4848
}
4949

5050
[HttpPost("{id}")]
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
55
<PreserveCompilationContext>true</PreserveCompilationContext>
66
<LangVersion>latest</LangVersion>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.18" />
1110
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
1211
</ItemGroup>
1312

13+
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
14+
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.14" />
15+
</ItemGroup>
16+
17+
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
18+
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.18" />
19+
</ItemGroup>
20+
1421
</Project>

tests/UnitTestEx.NUnit.Test/Other/GenericTest.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Configuration;
22
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Hosting;
34
using NUnit.Framework;
45
using System;
56
using System.Threading.Tasks;
@@ -39,7 +40,7 @@ public void Run_Exception()
3940
[Test]
4041
public void Run_Service()
4142
{
42-
using var test = GenericTester.Create().ConfigureServices(services => services.AddSingleton<Gin>());
43+
using var test = GenericTester.Create<EntryPoint>();
4344

4445
test.Run<Gin, int>(gin => gin.Pour())
4546
.AssertSuccess()
@@ -83,4 +84,15 @@ public void Shake() { }
8384
public int Pour() => 1;
8485
public Task<int> PourAsync() => Task.FromResult(1);
8586
}
87+
88+
public class EntryPoint
89+
{
90+
//public void ConfigureAppConfiguration(HostBuilderContext context, IConfigurationBuilder config) { }
91+
92+
//public void ConfigureHostConfiguration(IConfigurationBuilder config) { }
93+
94+
//public void ConfigureServices(IServiceCollection services) { }
95+
96+
public void ConfigureApplication(IHostApplicationBuilder builder) => builder.Services.AddSingleton<Gin>();
97+
}
8698
}

tests/UnitTestEx.NUnit.Test/UnitTestEx.NUnit.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<IsPackable>false</IsPackable>
66
<LangVersion>preview</LangVersion>
77
</PropertyGroup>

0 commit comments

Comments
 (0)