Skip to content

Commit 68bc9cd

Browse files
committed
fix issue with lazy init
1 parent c6cca41 commit 68bc9cd

File tree

5 files changed

+51
-77
lines changed

5 files changed

+51
-77
lines changed

src/TestHost.Abstracts/ITestHostApplication.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
namespace TestHost.Abstracts;
55

66
/// <summary>
7-
/// An interface for a test host application.
7+
/// An interface for a hosting a test application.
88
/// </summary>
9-
public interface ITestHostApplication
9+
public interface ITestHostApplication : IAsyncDisposable
1010
{
1111
/// <summary>
1212
/// Gets the host for the tests.

src/TestHost.Abstracts/Logging/MemoryLoggerExtensions.cs

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,53 +13,20 @@ public static class MemoryLoggerExtensions
1313
/// Adds a memory logger named 'MemoryLogger' to the factory.
1414
/// </summary>
1515
/// <param name="builder">The extension method argument.</param>
16+
/// <param name="configure">Optional configuration action for the <see cref="MemoryLoggerSettings"/>.</param>
1617
/// <returns>The <see cref="ILoggingBuilder"/> so that additional calls can be chained.</returns>
17-
public static ILoggingBuilder AddMemoryLogger(this ILoggingBuilder builder)
18+
public static ILoggingBuilder AddMemoryLogger(this ILoggingBuilder builder, Action<MemoryLoggerSettings>? configure = null)
1819
{
1920
if (builder is null)
2021
throw new ArgumentNullException(nameof(builder));
2122

22-
var descriptor = ServiceDescriptor.Singleton<ILoggerProvider, MemoryLoggerProvider>();
23+
builder.Services.AddOptions<MemoryLoggerSettings>();
2324

24-
builder.Services.TryAddEnumerable(descriptor);
25+
builder.Services.TryAddSingleton<MemoryLoggerProvider>();
26+
builder.Services.AddSingleton<ILoggerProvider>(sp => sp.GetRequiredService<MemoryLoggerProvider>());
2527

26-
return builder;
27-
}
28-
29-
/// <summary>
30-
/// Adds a memory logger. Use <paramref name="settings"/> to enable logging for specific <see cref="LogLevel"/>.
31-
/// </summary>
32-
/// <param name="builder">The extension method argument.</param>
33-
/// <param name="settings">The <see cref="MemoryLoggerSettings"/> to use.</param>
34-
/// <returns>The <see cref="ILoggingBuilder"/> so that additional calls can be chained.</returns>
35-
public static ILoggingBuilder AddMemoryLogger(this ILoggingBuilder builder, MemoryLoggerSettings settings)
36-
{
37-
if (builder is null)
38-
throw new ArgumentNullException(nameof(builder));
39-
if (settings is null)
40-
throw new ArgumentNullException(nameof(settings));
41-
42-
var logger = new MemoryLoggerProvider(settings);
43-
var descriptor = ServiceDescriptor.Singleton<ILoggerProvider>(logger);
44-
45-
builder.Services.TryAddEnumerable(descriptor);
46-
47-
return builder;
48-
}
49-
50-
/// <summary>
51-
/// Adds a memory logger. Use <paramref name="configure"/> to enable logging for specific <see cref="LogLevel"/>.
52-
/// </summary>
53-
/// <param name="builder">The extension method argument.</param>
54-
/// <param name="configure">A delegate to configure the <see cref="MemoryLoggerSettings"/>.</param>
55-
/// <returns>The <see cref="ILoggingBuilder"/> so that additional calls can be chained.</returns>
56-
public static ILoggingBuilder AddMemoryLogger(this ILoggingBuilder builder, Action<MemoryLoggerSettings> configure)
57-
{
58-
if (configure is null)
59-
throw new ArgumentNullException(nameof(configure));
60-
61-
builder.AddMemoryLogger();
62-
builder.Services.Configure(configure);
28+
if (configure is not null)
29+
builder.Services.Configure(configure);
6330

6431
return builder;
6532
}

src/TestHost.Abstracts/Logging/MemoryLoggerProvider.cs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,13 @@ public class MemoryLoggerProvider : ILoggerProvider, ISupportExternalScope
1717
private readonly MemoryLoggerSettings _settings;
1818
private IExternalScopeProvider? _scopeProvider;
1919

20-
/// <summary>
21-
/// Initializes a new instance of the <see cref="MemoryLoggerProvider"/> class.
22-
/// </summary>
23-
public MemoryLoggerProvider()
24-
: this(settings: null)
25-
{
26-
}
27-
28-
/// <summary>
29-
/// Initializes a new instance of the <see cref="MemoryLoggerProvider"/> class.
30-
/// </summary>
31-
/// <param name="settings">The <see cref="MemoryLoggerSettings"/>.</param>
32-
public MemoryLoggerProvider(MemoryLoggerSettings? settings)
33-
{
34-
_settings = settings ?? new MemoryLoggerSettings();
35-
}
36-
3720
/// <summary>
3821
/// Initializes a new instance of the <see cref="MemoryLoggerProvider"/> class.
3922
/// </summary>
4023
/// <param name="options">The <see cref="IOptions{MemoryLoggerSettings}"/>.</param>
4124
public MemoryLoggerProvider(IOptions<MemoryLoggerSettings> options)
42-
: this(options.Value)
4325
{
26+
_settings = options.Value ?? new MemoryLoggerSettings();
4427
}
4528

4629
/// <inheritdoc />
@@ -72,6 +55,8 @@ public void Clear()
7255
public void Dispose()
7356
{
7457
Clear();
58+
59+
GC.SuppressFinalize(this);
7560
}
7661

7762

@@ -91,7 +76,9 @@ private void WriteLog(MemoryLogEntry logEntry)
9176

9277
// ensure capacity
9378
while (_logEntries.Count > _settings.Capacity)
79+
{
9480
if (!_logEntries.TryDequeue(out _))
9581
break;
82+
}
9683
}
9784
}

src/TestHost.Abstracts/TestHostApplication.cs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,37 @@
66
namespace TestHost.Abstracts;
77

88
/// <summary>
9-
/// XUnit collection fixture that supports <see cref="HostApplicationBuilder"/>
9+
/// A base class for hosting a test application.
1010
/// </summary>
1111
public abstract class TestHostApplication : ITestHostApplication
1212
{
13-
private readonly Lazy<IHost> _host;
13+
#if NET9_0_OR_GREATER
14+
private readonly Lock _lockObject = new();
15+
#else
16+
private readonly object _lockObject = new();
17+
#endif
1418

15-
/// <summary>
16-
/// Initializes a new instance of the <see cref="TestHostApplication"/> class.
17-
/// </summary>
18-
protected TestHostApplication()
19-
{
20-
_host = new Lazy<IHost>(CreateHost);
21-
}
19+
private IHost? _host;
2220

2321
/// <summary>
2422
/// Gets the host for this test.
2523
/// </summary>
2624
/// <value>
2725
/// The host for this test.
2826
/// </value>
29-
public IHost Host => _host.Value;
27+
public IHost Host
28+
{
29+
get
30+
{
31+
if (_host != null)
32+
return _host;
33+
34+
lock (_lockObject)
35+
_host ??= CreateHost();
36+
37+
return _host;
38+
}
39+
}
3040

3141
/// <summary>
3242
/// Gets the services configured for this test
@@ -73,4 +83,17 @@ protected virtual void ConfigureApplication(HostApplicationBuilder builder)
7383
builder.Logging.SetMinimumLevel(LogLevel.Debug);
7484
builder.Logging.AddMemoryLogger();
7585
}
86+
87+
public virtual async ValueTask DisposeAsync()
88+
{
89+
if (_host == null)
90+
return;
91+
92+
await _host.StopAsync();
93+
94+
_host.Dispose();
95+
_host = null;
96+
97+
GC.SuppressFinalize(this);
98+
}
7699
}

test/TestHost.Abstracts.Tests/TestHostApplicationTests.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Microsoft.Extensions.DependencyInjection;
2-
using Microsoft.Extensions.Logging;
32

43
using TestHost.Abstracts.Logging;
54

@@ -21,15 +20,13 @@ public async Task GetService()
2120
await Assert.That(Service.IsRun).IsTrue();
2221
await Assert.That(ApplicationInitializer.IsStarted).IsTrue();
2322

24-
var memoryLogger = Application.Services
25-
.GetServices<ILoggerProvider>()
26-
.OfType<MemoryLoggerProvider>()
27-
.FirstOrDefault();
28-
23+
var memoryLogger = Application.Services.GetService<MemoryLoggerProvider>();
2924
await Assert.That(memoryLogger).IsNotNull();
3025

3126
var logs = memoryLogger?.GetEntries().ToList();
32-
3327
await Assert.That(logs).IsNotEmpty();
28+
29+
await Assert.That(logs).Contains(match => match.Message.Contains("Service Run()"));
30+
await Assert.That(logs).Contains(match => match.Message.Contains("Initialize Database StartAsync()"));
3431
}
3532
}

0 commit comments

Comments
 (0)