diff --git a/src/Foundatio.Xunit/Logging/LoggingExtensions.cs b/src/Foundatio.Xunit/Logging/LoggingExtensions.cs index 526434a8..fbe2959e 100644 --- a/src/Foundatio.Xunit/Logging/LoggingExtensions.cs +++ b/src/Foundatio.Xunit/Logging/LoggingExtensions.cs @@ -20,7 +20,23 @@ public static ILoggingBuilder AddTestLogger(this ILoggingBuilder builder, ITestO var options = new TestLoggerOptions { WriteLogEntryFunc = logEntry => { - outputHelper.WriteLine(logEntry.ToString(false)); + outputHelper?.WriteLine(logEntry.ToString(false)); + } + }; + + configure?.Invoke(options); + + return builder.AddTestLogger(options); + } + + public static ILoggingBuilder AddTestLogger(this ILoggingBuilder builder, Func getOutputHelper, + Action configure = null) + { + + var options = new TestLoggerOptions { + WriteLogEntryFunc = logEntry => + { + getOutputHelper?.Invoke()?.WriteLine(logEntry.ToString(false)); } }; diff --git a/src/Foundatio.Xunit/Logging/TestLogger.cs b/src/Foundatio.Xunit/Logging/TestLogger.cs index 11554a43..50506695 100644 --- a/src/Foundatio.Xunit/Logging/TestLogger.cs +++ b/src/Foundatio.Xunit/Logging/TestLogger.cs @@ -66,11 +66,12 @@ public int MaxLogEntriesToWrite public IReadOnlyList LogEntries => _logEntries.ToArray(); - public void Clear() + public void Reset() { lock (_logEntries) { _logEntries.Clear(); + _logLevels.Clear(); Interlocked.Exchange(ref _logEntriesWritten, 0); } } diff --git a/src/Foundatio.Xunit/Logging/TestLoggerBase.cs b/src/Foundatio.Xunit/Logging/TestLoggerBase.cs index 6aa2c907..c61855e7 100644 --- a/src/Foundatio.Xunit/Logging/TestLoggerBase.cs +++ b/src/Foundatio.Xunit/Logging/TestLoggerBase.cs @@ -13,7 +13,7 @@ protected TestLoggerBase(ITestOutputHelper output, TestLoggerFixture fixture) { Fixture = fixture; fixture.Output = output; - fixture.AddServiceRegistrations(RegisterServices); + fixture.ConfigureServices(ConfigureServices); } protected TestLoggerFixture Fixture { get; } @@ -21,7 +21,7 @@ protected TestLoggerBase(ITestOutputHelper output, TestLoggerFixture fixture) protected TestLogger TestLogger => Fixture.TestLogger; protected ILogger Log => Fixture.Log; - protected virtual void RegisterServices(IServiceCollection services) + protected virtual void ConfigureServices(IServiceCollection services) { } @@ -32,7 +32,7 @@ public virtual Task InitializeAsync() public virtual Task DisposeAsync() { - Fixture.TestLogger.Clear(); + Fixture.TestLogger.Reset(); return Task.CompletedTask; } } diff --git a/src/Foundatio.Xunit/Logging/TestLoggerFixture.cs b/src/Foundatio.Xunit/Logging/TestLoggerFixture.cs index 22388fdc..3e191e97 100644 --- a/src/Foundatio.Xunit/Logging/TestLoggerFixture.cs +++ b/src/Foundatio.Xunit/Logging/TestLoggerFixture.cs @@ -10,7 +10,7 @@ namespace Foundatio.Xunit; public class TestLoggerFixture : IAsyncLifetime { - private readonly List _disposables = []; + private readonly List _disposables = []; private readonly List> _serviceRegistrations = []; private readonly Lazy _serviceProvider; private readonly Lazy _testLogger; @@ -25,7 +25,7 @@ public TestLoggerFixture() public ITestOutputHelper Output { get; set; } - public void AddServiceRegistrations(Action registerServices) + public void ConfigureServices(Action registerServices) { _serviceRegistrations.Add(registerServices); } @@ -34,12 +34,9 @@ public void AddServiceRegistrations(Action registerServices) public TestLogger TestLogger => _testLogger.Value; public ILogger Log => _log.Value; - protected virtual void RegisterServices(IServiceCollection services) + protected virtual void ConfigureServices(IServiceCollection services) { - if (Output == null) - throw new InvalidOperationException("Output should be set before registering services."); - - services.AddLogging(c => c.AddTestLogger(Output)); + services.AddLogging(c => c.AddTestLogger(() => Output)); foreach (var registration in _serviceRegistrations) registration(services); } @@ -47,7 +44,7 @@ protected virtual void RegisterServices(IServiceCollection services) protected virtual IServiceProvider BuildServiceProvider() { var services = new ServiceCollection(); - RegisterServices(services); + ConfigureServices(services); var sp = services.BuildServiceProvider(); _disposables.Add(sp); return sp; @@ -58,20 +55,27 @@ public virtual Task InitializeAsync() return Task.CompletedTask; } - public virtual Task DisposeAsync() + public virtual async Task DisposeAsync() { - foreach (var disposable in _disposables) + foreach (object disposable in _disposables) { try { - disposable.Dispose(); + switch (disposable) + { + case IAsyncDisposable asyncDisposable: + await asyncDisposable.DisposeAsync(); + break; + case IDisposable syncDisposable: + syncDisposable.Dispose(); + break; + } } + catch (ObjectDisposedException) {} catch (Exception ex) { Log?.LogError(ex, "Error disposing resource."); } } - - return Task.CompletedTask; } } diff --git a/src/Foundatio.Xunit/Logging/TestLoggerOptions.cs b/src/Foundatio.Xunit/Logging/TestLoggerOptions.cs index f8489c66..1929ea60 100644 --- a/src/Foundatio.Xunit/Logging/TestLoggerOptions.cs +++ b/src/Foundatio.Xunit/Logging/TestLoggerOptions.cs @@ -1,6 +1,7 @@ using System; using Foundatio.Utility; using Microsoft.Extensions.Logging; +using Xunit.Abstractions; namespace Foundatio.Xunit; @@ -11,6 +12,15 @@ public class TestLoggerOptions public int MaxLogEntriesToWrite { get; set; } = 1000; public bool IncludeScopes { get; set; } = true; + public void UseOutputHelper(Func getOutputHelper, Func formatLogEntry = null) + { + formatLogEntry ??= logEntry => logEntry.ToString(false); + WriteLogEntryFunc = logEntry => + { + getOutputHelper?.Invoke()?.WriteLine(formatLogEntry(logEntry)); + }; + } + public Action WriteLogEntryFunc { get; set; } internal void WriteLogEntry(LogEntry logEntry) => WriteLogEntryFunc?.Invoke(logEntry); diff --git a/tests/Foundatio.Tests/Utility/TestLoggerTests.cs b/tests/Foundatio.Tests/Utility/TestLoggerTests.cs index 3e3f23f3..0ea59066 100644 --- a/tests/Foundatio.Tests/Utility/TestLoggerTests.cs +++ b/tests/Foundatio.Tests/Utility/TestLoggerTests.cs @@ -15,7 +15,7 @@ public class TestLoggerTests : TestLoggerBase public TestLoggerTests(ITestOutputHelper output, TestLoggerFixture fixture) : base(output, fixture) { _output = output; - fixture.AddServiceRegistrations(s => s.AddSingleton()); + fixture.ConfigureServices(s => s.AddSingleton()); } [Fact] @@ -35,7 +35,7 @@ public void CanUseTestLogger() Assert.Single(testLogger.LogEntries); Assert.Contains("Doing something", testLogger.LogEntries[0].Message); - testLogger.Clear(); + testLogger.Reset(); testLogger.SetLogLevel(LogLevel.Error); someClass.DoSomething(2); @@ -56,7 +56,7 @@ public void CanUseTestLoggerFixture() Assert.Equal(100, TestLogger.LogEntries.Count); Assert.Contains("Hello 2", TestLogger.LogEntries.Last().Message); - Fixture.TestLogger.Clear(); + Fixture.TestLogger.Reset(); TestLogger.SetLogLevel(LogLevel.Error); someClass.DoSomething(1002); @@ -75,7 +75,7 @@ public void CanUseTestLoggerFixture2() Assert.Single(TestLogger.LogEntries); Assert.Contains("Doing something", TestLogger.LogEntries[0].Message); - TestLogger.Clear(); + TestLogger.Reset(); TestLogger.SetLogLevel(LogLevel.Error); someClass.DoSomething(2);