Skip to content

Commit e259795

Browse files
authored
feat: Added support for keyed services (#1374)
1 parent 27f8bb6 commit e259795

File tree

6 files changed

+85
-5
lines changed

6 files changed

+85
-5
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ jobs:
109109
- name: Validate package
110110
shell: pwsh
111111
run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NUGET_DIRECTORY }}/*.nupkg") --excluded-rules IconMustBeSet
112-
112+
113113
run-test:
114114
strategy:
115115
fail-fast: false
@@ -134,7 +134,7 @@ jobs:
134134
8.0.x
135135
136136
- name: 🧪 Run unit tests
137-
run: dotnet test -c release
137+
run: dotnet test -c release --blame --blame-crash --blame-hang
138138

139139
- name: 📛 Upload hang- and crash-dumps on test failure
140140
if: failure()

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ All notable changes to **bUnit** will be documented in this file. The project ad
66

77
## [Unreleased]
88

9+
### Added
10+
- Support for `IKeyedServiceProvider` in net8.0. Reported by [@ViRuSTriNiTy](https://github.com/ViRuSTriNiTy). By [@linkdotnet](https://github.com/linkdotnet).
11+
912
## [1.26.64] - 2023-12-20
1013

1114
### Changed

src/bunit.core/TestServiceProvider.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ namespace Bunit;
66
/// Represents a <see cref="IServiceProvider"/> and <see cref="IServiceCollection"/>
77
/// as a single type used for test purposes.
88
/// </summary>
9+
#if !NET8_0_OR_GREATER
910
public sealed class TestServiceProvider : IServiceProvider, IServiceCollection, IDisposable, IAsyncDisposable
11+
#else
12+
public sealed class TestServiceProvider : IKeyedServiceProvider, IServiceCollection, IDisposable, IAsyncDisposable
13+
#endif
1014
{
1115
private static readonly ServiceProviderOptions DefaultServiceProviderOptions = new() { ValidateScopes = true };
1216
private readonly IServiceCollection serviceCollection;
@@ -230,6 +234,35 @@ public bool Remove(ServiceDescriptor item)
230234
return serviceCollection.Remove(item);
231235
}
232236

237+
#if NET8_0_OR_GREATER
238+
/// <inheritdoc/>
239+
public object? GetKeyedService(Type serviceType, object? serviceKey)
240+
{
241+
if (serviceProvider is null)
242+
InitializeProvider();
243+
244+
if (serviceProvider is IKeyedServiceProvider keyedServiceProvider)
245+
{
246+
var value = keyedServiceProvider.GetKeyedService(serviceType, serviceKey);
247+
if (value is not null)
248+
return value;
249+
}
250+
251+
if (fallbackServiceProvider is IKeyedServiceProvider fallbackKeyedServiceProvider)
252+
return fallbackKeyedServiceProvider.GetKeyedService(serviceType, serviceKey);
253+
254+
return default;
255+
}
256+
257+
/// <inheritdoc/>
258+
public object GetRequiredKeyedService(Type serviceType, object? serviceKey)
259+
{
260+
var service = GetKeyedService(serviceType, serviceKey) ?? throw new InvalidOperationException($"No service for type '{serviceType}' and key '{serviceKey}' has been registered.");
261+
262+
return service;
263+
}
264+
#endif
265+
233266
private void CheckInitializedAndThrow()
234267
{
235268
if (IsProviderInitialized)

tests/.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ dotnet_diagnostic.CA2007.severity = none # https://github.com/atc-net
4242

4343
dotnet_diagnostic.CA1819.severity = suggestion # CA1819: Properties should not return arrays
4444
dotnet_diagnostic.CA1849.severity = suggestion # CA1849: Call async methods when in an async method
45+
dotnet_diagnostic.CA2255.severity = suggestion # CA2255: The 'ModuleInitializer' attribute is only intended to be used in application code or advanced source generator scenarios
4546
dotnet_diagnostic.xUnit1026.severity = none # xUnit1026: Theory methods should use all of their parameters
4647
dotnet_diagnostic.xUnit1034.severity = none # xUnit1034: Null should not be used for type parameter
4748
dotnet_diagnostic.S1144.severity = suggestion # S1144: Unused private types or members should be removed

tests/bunit.core.tests/TestServiceProviderTest.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,40 @@ public void Test039()
296296
dummyServiceProvider.ResolvedTestServices.ShouldContain(result);
297297
dummyServiceProvider.ResolvedTestServices.Count.ShouldBe(1);
298298
}
299+
300+
#if NET8_0_OR_GREATER
301+
[Fact(DisplayName = "Should resolve keyed service from container")]
302+
public void Test040()
303+
{
304+
using var ctx = new TestContext();
305+
ctx.Services.AddKeyedScoped<DummyService>("Key");
306+
307+
var cut = ctx.RenderComponent<ComponentWithKeyedService>();
308+
309+
cut.Instance.Service.ShouldNotBeNull();
310+
}
311+
312+
[Fact(DisplayName = "Should resolved keyed service from fallback service provider")]
313+
public void Test041()
314+
{
315+
using var ctx = new TestContext();
316+
var fallbackCollection = new ServiceCollection();
317+
fallbackCollection.AddKeyedScoped<DummyService>("Key");
318+
ctx.Services.AddFallbackServiceProvider(fallbackCollection.BuildServiceProvider());
319+
320+
var cut = ctx.RenderComponent<ComponentWithKeyedService>();
321+
322+
cut.Instance.Service.ShouldNotBeNull();
323+
}
324+
325+
[Fact(DisplayName = "Throw an exception if required keyed service is not found")]
326+
public void Test042()
327+
{
328+
using var ctx = new TestContext();
329+
330+
Should.Throw<InvalidOperationException>(() => ctx.RenderComponent<ComponentWithKeyedService>());
331+
}
332+
#endif
299333

300334
private sealed class DummyService { }
301335

@@ -381,4 +415,12 @@ public DummyServiceProviderFactoryContainerBuilder CreateBuilder(IServiceCollect
381415
public IServiceProvider CreateServiceProvider(DummyServiceProviderFactoryContainerBuilder containerBuilder)
382416
=> containerBuilder.Build();
383417
}
418+
419+
#if NET8_0_OR_GREATER
420+
private sealed class ComponentWithKeyedService : ComponentBase
421+
{
422+
[Inject(Key = "Key")]
423+
public DummyService Service { get; set; }
424+
}
425+
#endif
384426
}

tests/bunit.generators.tests/bunit.generators.tests.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
55
<RootNamespace>Bunit</RootNamespace>
6-
<AssemblyName>Bunit.Web.AngleSharp.Tests</AssemblyName>
6+
<AssemblyName>Bunit.Generator.Tests</AssemblyName>
77
<ImplicitUsings>true</ImplicitUsings>
88
<SonarQubeTestProject>true</SonarQubeTestProject>
99
<IsPackable>false</IsPackable>
@@ -13,19 +13,20 @@
1313
</PropertyGroup>
1414

1515
<ItemGroup>
16+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
1617
<PackageReference Include="System.Net.Http" Version="4.3.4" />
1718
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
1819
<PackageReference Include="Verify.SourceGenerators" Version="2.2.0" />
1920
<PackageReference Include="Verify.Xunit" Version="23.1.0" />
20-
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0" />
21+
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.2" />
2122
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
2223
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.8.0" />
2324
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.8.0" />
2425
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
2526
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.1" />
2627

2728
<PackageReference Include="xunit" Version="2.6.6" />
28-
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
29+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
2930
<PrivateAssets>all</PrivateAssets>
3031
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
3132
</PackageReference>

0 commit comments

Comments
 (0)