diff --git a/.nuget/Cuemon.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xunit.Hosting/PackageReleaseNotes.txt
index 6ae8375d5..21ab2ae7b 100644
--- a/.nuget/Cuemon.Extensions.Xunit.Hosting/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Xunit.Hosting/PackageReleaseNotes.txt
@@ -6,6 +6,7 @@ Availability: .NET 9, .NET 8, .NET 6 and .NET Standard 2.0
# New Features
- ADDED ServiceProviderExtensions class in the Cuemon.Extensions.Xunit.Hosting namespace that consist of one extension method for the IServiceProvider interface: GetRequiredScopedService
+- EXTENDED ServiceCollectionExtensions class in the Cuemon.Extensions.Xunit.Hosting namespace with three new extension methods for the IServiceCollection interface: AddXunitTestOutputHelperAccessor, AddXunitTestOutputHelperAccessor{T} and an overload of AddXunitTestOutputHelperAccessor
Version 8.3.2
Availability: .NET 8, .NET 6 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Xunit/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xunit/PackageReleaseNotes.txt
index 572ceda20..63c7d6ceb 100644
--- a/.nuget/Cuemon.Extensions.Xunit/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Xunit/PackageReleaseNotes.txt
@@ -7,6 +7,10 @@ Availability: .NET 9, .NET 8, .NET 6 and .NET Standard 2.0
# Improvements
- EXTENDED TestOutputHelperExtensions class in the Cuemon.Extensions.Xunit namespace with an additional overloaded method: WriteLines
+# New Features
+- ADDED ITestOutputHelperAccessor interface in the Cuemon.Extensions.Xunit namespace that provides access to the ITestOutputHelper instance
+- ADDED TestOutputHelperAccessor class in the Cuemon.Extensions.Xunit namespace that provides a default implementation of the ITestOutputHelper interface
+
Version 8.3.2
Availability: .NET 8, .NET 6 and .NET Standard 2.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0b0f6f57..e66caa308 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,10 @@ New features:
- FailureConverter class in the Cuemon.Extensions.Text.Json.Converters namespace to convert FailureConverter to JSON
- FailureConverter class in the Cuemon.Xml.Serialization.Converters namespace to convert FailureConverter to XML
- Support for System.Threading.Lock object that targets TFMs prior to .NET 9 (credits to Mark Cilia Vincenti, https://github.com/MarkCiliaVincenti/Backport.System.Threading.Lock)
+- ITestOutputHelperAccessor interface in the Cuemon.Extensions.Xunit namespace that provides access to the ITestOutputHelper instance
+- TestOutputHelperAccessor class in the Cuemon.Extensions.Xunit namespace that provides a default implementation of the ITestOutputHelper interface
+- ServiceProviderExtensions class in the Cuemon.Extensions.Xunit.Hosting namespace that consist of one extension method for the IServiceProvider interface: GetRequiredScopedService
+- ServiceCollectionExtensions class in the Cuemon.Extensions.Xunit.Hosting namespace was extended with three new extension methods for the IServiceCollection interface: AddXunitTestOutputHelperAccessor, AddXunitTestOutputHelperAccessor{T} and an overload of AddXunitTestOutputHelperAccessor
### Changed
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj
index b519913ee..a447e3092 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj b/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj
index c879eb7ea..d8ad566e2 100644
--- a/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj
+++ b/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj b/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj
index d30d380eb..6a2cbd0ef 100644
--- a/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj
+++ b/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj b/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj
index 14dab98e8..460d7e81d 100644
--- a/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj
+++ b/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Cuemon.Extensions.Text.Json/Cuemon.Extensions.Text.Json.csproj b/src/Cuemon.Extensions.Text.Json/Cuemon.Extensions.Text.Json.csproj
index 8cd21616c..ec195212d 100644
--- a/src/Cuemon.Extensions.Text.Json/Cuemon.Extensions.Text.Json.csproj
+++ b/src/Cuemon.Extensions.Text.Json/Cuemon.Extensions.Text.Json.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore/Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj b/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore/Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj
index b85bf0488..ffed3069f 100644
--- a/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore/Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj
+++ b/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore/Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/src/Cuemon.Extensions.Xunit.Hosting/Cuemon.Extensions.Xunit.Hosting.csproj b/src/Cuemon.Extensions.Xunit.Hosting/Cuemon.Extensions.Xunit.Hosting.csproj
index 1b5e7f71c..ee24a2cf2 100644
--- a/src/Cuemon.Extensions.Xunit.Hosting/Cuemon.Extensions.Xunit.Hosting.csproj
+++ b/src/Cuemon.Extensions.Xunit.Hosting/Cuemon.Extensions.Xunit.Hosting.csproj
@@ -11,11 +11,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/src/Cuemon.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs
index 7552e0131..60ac253e1 100644
--- a/src/Cuemon.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs
+++ b/src/Cuemon.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs
@@ -32,5 +32,55 @@ public static IServiceCollection AddXunitTestLogging(this IServiceCollection ser
});
return services;
}
+
+ ///
+ /// Adds a unit test optimized implementation of output logging to the collection.
+ ///
+ /// The to extend.
+ /// The that provides access to the output for the logging.
+ /// The that specifies the minimum level to include for the logging.
+ /// A reference to so that additional configuration calls can be chained.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, ITestOutputHelperAccessor accessor, LogLevel minimumLevel = LogLevel.Trace)
+ {
+ Validator.ThrowIfNull(services);
+ Validator.ThrowIfNull(accessor);
+ services.AddLogging(builder =>
+ {
+ builder.SetMinimumLevel(minimumLevel);
+ builder.AddProvider(new XunitTestLoggerProvider(accessor));
+ });
+ return services;
+ }
+
+ ///
+ /// Adds a default implementation of to the collection.
+ ///
+ /// The to extend.
+ /// A reference to so that additional configuration calls can be chained.
+ public static IServiceCollection AddXunitTestOutputHelperAccessor(this IServiceCollection services)
+ {
+ services.AddXunitTestOutputHelperAccessor();
+ return services;
+ }
+
+ ///
+ /// Adds a specified implementation of to the collection.
+ ///
+ /// The type of the implementation of .
+ /// The to extend.
+ /// A reference to so that additional configuration calls can be chained.
+ ///
+ /// cannot be null.
+ ///
+ public static IServiceCollection AddXunitTestOutputHelperAccessor(this IServiceCollection services) where T : class, ITestOutputHelperAccessor
+ {
+ Validator.ThrowIfNull(services);
+ services.AddSingleton();
+ return services;
+ }
}
}
diff --git a/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLogger.cs b/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLogger.cs
index eea1d18cd..8af387b57 100644
--- a/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLogger.cs
+++ b/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLogger.cs
@@ -7,6 +7,7 @@ namespace Cuemon.Extensions.Xunit.Hosting
{
internal class XunitTestLogger : InMemoryTestStore, ILogger, IDisposable
{
+ private readonly ITestOutputHelperAccessor _accessor;
private readonly ITestOutputHelper _output;
public XunitTestLogger(ITestOutputHelper output)
@@ -14,13 +15,25 @@ public XunitTestLogger(ITestOutputHelper output)
_output = output;
}
+ public XunitTestLogger(ITestOutputHelperAccessor accessor)
+ {
+ _accessor = accessor;
+ }
+
public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
{
var builder = new StringBuilder($"{logLevel}: {formatter(state, exception)}");
if (exception != null) { builder.AppendLine().Append(exception).AppendLine(); }
var message = builder.ToString();
- _output.WriteLine(message);
+ if (_accessor != null)
+ {
+ _accessor.TestOutput.WriteLine(message);
+ }
+ else
+ {
+ _output.WriteLine(message);
+ }
Add(new XunitTestLoggerEntry(logLevel, eventId, message));
}
diff --git a/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs b/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs
index 86e77b574..a3c1cdc8e 100644
--- a/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs
+++ b/src/Cuemon.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs
@@ -7,6 +7,7 @@ namespace Cuemon.Extensions.Xunit.Hosting
internal class XunitTestLoggerProvider : ILoggerProvider
{
private readonly ConcurrentDictionary _loggers = new();
+ private readonly ITestOutputHelperAccessor _accessor;
private readonly ITestOutputHelper _output;
public XunitTestLoggerProvider(ITestOutputHelper output)
@@ -14,9 +15,16 @@ public XunitTestLoggerProvider(ITestOutputHelper output)
_output = output;
}
+ public XunitTestLoggerProvider(ITestOutputHelperAccessor accessor)
+ {
+ _accessor = accessor;
+ }
+
public ILogger CreateLogger(string categoryName)
{
- return _loggers.GetOrAdd(categoryName, s => new XunitTestLogger(_output));
+ return _loggers.GetOrAdd(categoryName, _ => _accessor != null
+ ? new XunitTestLogger(_accessor)
+ : new XunitTestLogger(_output));
}
public void Dispose()
diff --git a/src/Cuemon.Extensions.Xunit/ITestOutputHelperAccessor.cs b/src/Cuemon.Extensions.Xunit/ITestOutputHelperAccessor.cs
new file mode 100644
index 000000000..41641ee32
--- /dev/null
+++ b/src/Cuemon.Extensions.Xunit/ITestOutputHelperAccessor.cs
@@ -0,0 +1,16 @@
+using Xunit.Abstractions;
+
+namespace Cuemon.Extensions.Xunit
+{
+ ///
+ /// Provides an interface for accessing the instance.
+ ///
+ public interface ITestOutputHelperAccessor
+ {
+ ///
+ /// Gets or sets the instance used for outputting test results.
+ ///
+ /// The instance.
+ ITestOutputHelper TestOutput { get; set; }
+ }
+}
diff --git a/src/Cuemon.Extensions.Xunit/TestOutputHelperAccessor.cs b/src/Cuemon.Extensions.Xunit/TestOutputHelperAccessor.cs
new file mode 100644
index 000000000..55a6c546d
--- /dev/null
+++ b/src/Cuemon.Extensions.Xunit/TestOutputHelperAccessor.cs
@@ -0,0 +1,32 @@
+using System.Threading;
+using Xunit.Abstractions;
+
+namespace Cuemon.Extensions.Xunit
+{
+ ///
+ /// Provides a default implementation of the interface.
+ ///
+ public class TestOutputHelperAccessor : ITestOutputHelperAccessor
+ {
+ private static readonly AsyncLocal Current = new();
+
+ ///
+ /// Initializes a new instance of the class with the specified instance.
+ ///
+ /// The instance to be used for outputting test results.
+ public TestOutputHelperAccessor(ITestOutputHelper output = null)
+ {
+ Current.Value = output;
+ }
+
+ ///
+ /// Gets or sets the instance used for outputting test results.
+ ///
+ /// The instance.
+ public ITestOutputHelper TestOutput
+ {
+ get => Current.Value;
+ set => Current.Value = value;
+ }
+ }
+}
diff --git a/test/Cuemon.Data.Tests/Cuemon.Data.Tests.csproj b/test/Cuemon.Data.Tests/Cuemon.Data.Tests.csproj
index a9d822e51..46c6044ee 100644
--- a/test/Cuemon.Data.Tests/Cuemon.Data.Tests.csproj
+++ b/test/Cuemon.Data.Tests/Cuemon.Data.Tests.csproj
@@ -26,15 +26,15 @@
-
+
-
+
-
+
diff --git a/test/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostTestTest.cs b/test/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostTestTest.cs
index 059e3bd1b..50c8f8e14 100644
--- a/test/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostTestTest.cs
+++ b/test/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostTestTest.cs
@@ -6,6 +6,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Xunit;
using Xunit.Abstractions;
@@ -21,6 +22,8 @@ public AspNetCoreHostTestTest(AspNetCoreHostFixture hostFixture, ITestOutputHelp
{
_pipeline = hostFixture.Application;
_provider = hostFixture.ServiceProvider;
+
+ _provider.GetRequiredService().TestOutput = output;
}
[Fact]
@@ -30,7 +33,7 @@ public async Task ShouldHaveResultOfBoolMiddlewareInBody()
var options = _provider.GetRequiredService>();
var pipeline = _pipeline.Build();
- Assert.Equal("Hello awesome developers!", context.Response.Body.ToEncodedString(o => o.LeaveOpen = true));
+ Assert.Equal("Hello awesome developers!", context!.Response.Body.ToEncodedString(o => o.LeaveOpen = true));
await pipeline(context);
@@ -44,8 +47,16 @@ public async Task ShouldHaveResultOfBoolMiddlewareInBody()
Assert.False(options.Value.F);
}
+ [Fact]
+ public void ShouldLogToXunitTestLogging()
+ {
+ var logger = _pipeline.ApplicationServices.GetRequiredService>();
+ logger.LogInformation("Hello from {0}", nameof(ShouldLogToXunitTestLogging));
+ }
+
public override void ConfigureApplication(IApplicationBuilder app)
{
+ app.ApplicationServices.GetRequiredService>().LogInformation(nameof(ConfigureApplication));
app.UseMiddleware();
}
@@ -58,6 +69,8 @@ public override void ConfigureServices(IServiceCollection services)
o.C = true;
o.E = true;
});
+ services.AddXunitTestOutputHelperAccessor();
+ services.AddXunitTestLogging(new TestOutputHelperAccessor(TestOutput));
}
}
-}
\ No newline at end of file
+}
diff --git a/testenvironments.json b/testenvironments.json
index 682fcd417..b5827e2ef 100644
--- a/testenvironments.json
+++ b/testenvironments.json
@@ -9,7 +9,7 @@
{
"name": "Docker-Ubuntu",
"type": "docker",
- "dockerImage": "gimlichael/ubuntu-testrunner:net6.0.425-net8.0.401-9.0.100-preview.7.24407.12"
+ "dockerImage": "gimlichael/ubuntu-testrunner:net6.0.425-net8.0.401-9.0.100-rc.1.24452.12"
}
]
}