Skip to content

Commit 48e819c

Browse files
authored
feat: Add ability to pass ServiceProviderOptions to TestServiceProvider
Fixed #574
1 parent 471e7d9 commit 48e819c

5 files changed

Lines changed: 71 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ All notable changes to **bUnit** will be documented in this file. The project ad
99
### Added
1010

1111
- Add `ComponentFactories` extensions method that makes it easy to register an instance of a replacement component. By [@egil](https://github.com/egil).
12+
- Add ability to pass `ServiceProviderOptions` to `TestServiceProvider` through property to allow users to customize the service provider. By [@rodolfograve](https://github.com/rodolfograve).
1213

1314
### Fixed
1415

src/bunit.core/TestServiceProvider.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ namespace Bunit;
88
/// </summary>
99
public sealed class TestServiceProvider : IServiceProvider, IServiceCollection, IDisposable
1010
{
11+
private readonly static ServiceProviderOptions DefaultServiceProviderOptions = new() { ValidateScopes = true };
1112
private readonly IServiceCollection serviceCollection;
1213
private IServiceProvider? rootServiceProvider;
1314
private IServiceScope? serviceScope;
1415
private IServiceProvider? serviceProvider;
1516
private IServiceProvider? fallbackServiceProvider;
17+
private ServiceProviderOptions options = DefaultServiceProviderOptions;
1618

1719
/// <summary>
1820
/// Gets a value indicating whether this <see cref="TestServiceProvider"/> has been initialized, and
@@ -37,6 +39,15 @@ public ServiceDescriptor this[int index]
3739
}
3840
}
3941

42+
/// <summary>
43+
/// Gets or sets the <see cref="ServiceProviderOptions"/> used when the <see cref="IServiceProvider"/> is created.
44+
/// </summary>
45+
public ServiceProviderOptions Options
46+
{
47+
get => options;
48+
set => options = value ?? DefaultServiceProviderOptions;
49+
}
50+
4051
/// <summary>
4152
/// Initializes a new instance of the <see cref="TestServiceProvider"/> class
4253
/// and sets its service collection to the provided <paramref name="initialServiceCollection"/>, if any.
@@ -83,7 +94,7 @@ public object GetService(Type serviceType)
8394
if (serviceProvider is null)
8495
{
8596
serviceCollection.AddSingleton<TestServiceProvider>(this);
86-
rootServiceProvider = serviceCollection.BuildServiceProvider(validateScopes: true);
97+
rootServiceProvider = serviceCollection.BuildServiceProvider(options);
8798
serviceScope = rootServiceProvider.CreateScope();
8899
serviceProvider = serviceScope.ServiceProvider;
89100
}

tests/bunit.core.tests/TestContextBaseTest.net5.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1+
12
#if NET5_0_OR_GREATER
2-
using System;
3-
using Bunit.Extensions;
4-
using Bunit.TestAssets.SampleComponents;
5-
using Microsoft.AspNetCore.Components;
6-
using Moq;
7-
using Xunit;
83

94
namespace Bunit;
105

tests/bunit.core.tests/TestServiceProviderTest.cs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ private class AnotherDummyService { }
1010

1111
private class OneMoreDummyService { }
1212

13+
private class DummyServiceWithDependencyOnAnotherDummyService
14+
{
15+
public DummyServiceWithDependencyOnAnotherDummyService(AnotherDummyService anotherDummyService)
16+
{
17+
}
18+
}
19+
1320
private class FallbackServiceProvider : IServiceProvider
1421
{
1522
public object GetService(Type serviceType) => new DummyService();
@@ -25,6 +32,16 @@ private class DummyComponentWhichRequiresDummyService : ComponentBase
2532
[Inject] public DummyService Service { get; set; }
2633
}
2734

35+
private sealed class DisposableService : IDisposable
36+
{
37+
public bool IsDisposed { get; private set; }
38+
39+
public void Dispose()
40+
{
41+
IsDisposed = true;
42+
}
43+
}
44+
2845
[Fact(DisplayName = "Provider initialized without a service collection has zero services by default")]
2946
public void Test001()
3047
{
@@ -240,13 +257,48 @@ public void Test033()
240257
disposable.IsDisposed.ShouldBeTrue();
241258
}
242259

243-
private sealed class DisposableService : IDisposable
260+
[Fact(DisplayName = "Validates that all dependencies can be created when the first service is requested, if ServiceProviderOptions.ValidateOnBuild is true")]
261+
public void Test035()
244262
{
245-
public bool IsDisposed { get; private set; }
263+
using var sut = new TestServiceProvider();
264+
sut.Options = new ServiceProviderOptions
265+
{
266+
ValidateOnBuild = true,
267+
ValidateScopes = true
268+
};
269+
sut.AddSingleton<DummyService>();
270+
sut.AddSingleton<DummyServiceWithDependencyOnAnotherDummyService>();
271+
var action = () => sut.GetRequiredService<DummyService>();
272+
273+
action.ShouldThrow<AggregateException>("Some services are not able to be constructed (Error while validating the service descriptor");
274+
}
246275

247-
public void Dispose()
276+
[Fact(DisplayName ="Does not validate all dependencies can be created when the first service is requested, if ServiceProviderOptions.ValidateOnBuild is false")]
277+
public void Test036()
278+
{
279+
using var sut = new TestServiceProvider();
280+
sut.Options = new ServiceProviderOptions
248281
{
249-
IsDisposed = true;
250-
}
282+
ValidateOnBuild = false,
283+
ValidateScopes = true
284+
};
285+
sut.AddSingleton<DummyService>();
286+
sut.AddSingleton<DummyServiceWithDependencyOnAnotherDummyService>();
287+
288+
var result = sut.GetRequiredService<DummyService>();
289+
290+
result.ShouldNotBeNull();
291+
}
292+
293+
[Fact(DisplayName ="Does not validate all dependencies can be created when the first service is requested, if no ServiceProviderOptions is provided (backwards compatibility)")]
294+
public void Test037()
295+
{
296+
using var sut = new TestServiceProvider();
297+
sut.AddSingleton<DummyService>();
298+
sut.AddSingleton<DummyServiceWithDependencyOnAnotherDummyService>();
299+
300+
var result = sut.GetRequiredService<DummyService>();
301+
302+
result.ShouldNotBeNull();
251303
}
252304
}

tests/bunit.core.tests/TestServiceProviderTest.net5.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
#if NET5_0_OR_GREATER
2-
using System;
3-
using System.Threading.Tasks;
4-
using Microsoft.Extensions.DependencyInjection;
5-
using Shouldly;
6-
using Xunit;
7-
82
namespace Bunit;
93

104
public partial class TestServiceProviderTest

0 commit comments

Comments
 (0)