From dc7dd83203d76a36a9735334fd655be7b5951978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Frajt=C3=A1k?= <1510452+kfrajtak@users.noreply.github.com> Date: Mon, 16 Jun 2025 13:55:57 +0200 Subject: [PATCH] using Xunit test output helper for logging --- .../WorkflowCore.Testing.csproj | 6 ++ src/WorkflowCore.Testing/WorkflowTest.cs | 10 +- src/WorkflowCore.Testing/XUnitLogger.cs | 91 +++++++++++++++++++ .../Scenarios/DelayScenario.cs | 5 +- .../Scenarios/MongoDelayScenario.cs | 3 +- .../Scenarios/MysqlDelayScenario.cs | 5 + .../Scenarios/OracleDelayScenario.cs | 7 +- .../Scenarios/PostgresDelayScenario.cs | 7 +- .../Scenarios/SqlServerDelayScenario.cs | 7 +- .../Scenarios/SqliteDelayScenario.cs | 26 ++++++ 10 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 src/WorkflowCore.Testing/XUnitLogger.cs create mode 100644 test/WorkflowCore.Tests.Sqlite/Scenarios/SqliteDelayScenario.cs diff --git a/src/WorkflowCore.Testing/WorkflowCore.Testing.csproj b/src/WorkflowCore.Testing/WorkflowCore.Testing.csproj index 6102c9892..2f52d6592 100644 --- a/src/WorkflowCore.Testing/WorkflowCore.Testing.csproj +++ b/src/WorkflowCore.Testing/WorkflowCore.Testing.csproj @@ -19,4 +19,10 @@ + + + ..\..\..\..\..\.nuget\packages\xunit.abstractions\2.0.3\lib\netstandard2.0\xunit.abstractions.dll + + + diff --git a/src/WorkflowCore.Testing/WorkflowTest.cs b/src/WorkflowCore.Testing/WorkflowTest.cs index bf0eb97ab..7b0746d31 100644 --- a/src/WorkflowCore.Testing/WorkflowTest.cs +++ b/src/WorkflowCore.Testing/WorkflowTest.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using WorkflowCore.Interface; using WorkflowCore.Models; +using Xunit.Abstractions; namespace WorkflowCore.Testing { @@ -18,11 +19,16 @@ public abstract class WorkflowTest : IDisposable protected IPersistenceProvider PersistenceProvider; protected List UnhandledStepErrors = new List(); - protected virtual void Setup() + protected virtual void Setup(ITestOutputHelper testOutputHelper = null) { //setup dependency injection IServiceCollection services = new ServiceCollection(); - services.AddLogging(); + services.AddLogging(l => l.SetMinimumLevel(LogLevel.Trace)); + services.AddSingleton(p => new XUnitLoggerProvider(testOutputHelper)); + services.Add(ServiceDescriptor.Singleton()); + services.Add(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(XUnitLogger<>))); + services.AddSingleton(sp => testOutputHelper); + ConfigureServices(services); var serviceProvider = services.BuildServiceProvider(); diff --git a/src/WorkflowCore.Testing/XUnitLogger.cs b/src/WorkflowCore.Testing/XUnitLogger.cs new file mode 100644 index 000000000..d160a0c55 --- /dev/null +++ b/src/WorkflowCore.Testing/XUnitLogger.cs @@ -0,0 +1,91 @@ +using System; +using System.Text; +using Microsoft.Extensions.Logging; +using Xunit.Abstractions; + +namespace WorkflowCore.Testing +{ + internal class XUnitLogger : ILogger + { + private readonly ITestOutputHelper _testOutputHelper; + private readonly string _categoryName; + private readonly LoggerExternalScopeProvider _scopeProvider; + + public static ILogger CreateLogger(ITestOutputHelper testOutputHelper) => + new XUnitLogger(testOutputHelper, new LoggerExternalScopeProvider(), ""); + + public static ILogger CreateLogger(ITestOutputHelper testOutputHelper) => + new XUnitLogger(testOutputHelper, new LoggerExternalScopeProvider()); + + public XUnitLogger(ITestOutputHelper testOutputHelper, LoggerExternalScopeProvider scopeProvider, + string categoryName) + { + _testOutputHelper = testOutputHelper; + _scopeProvider = scopeProvider; + _categoryName = categoryName; + } + + public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None; + + public IDisposable BeginScope(TState state) => _scopeProvider.Push(state); + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, + Func formatter) + { + if (_testOutputHelper == null) return; + var sb = new StringBuilder(); + sb.Append(DateTime.Now.ToString("HH:mm:ss.fff")) + .Append(" ") + .Append(GetLogLevelString(logLevel)) + .Append(" [").Append(_categoryName).Append("] ") + .Append(formatter(state, exception)); + + if (exception != null) + { + sb.Append('\n').Append(exception); + } + + // Append scopes + _scopeProvider.ForEachScope((scope, s) => + { + s.Append("\n => "); + s.Append(scope); + }, sb); + + _testOutputHelper.WriteLine(sb.ToString()); + } + + private static string GetLogLevelString(LogLevel logLevel) + { + return logLevel.ToString().ToUpper(); + } + } + + internal sealed class XUnitLogger : XUnitLogger, ILogger + { + public XUnitLogger(ITestOutputHelper testOutputHelper, LoggerExternalScopeProvider scopeProvider) + : base(testOutputHelper, scopeProvider, typeof(T).FullName) + { + } + } + + internal sealed class XUnitLoggerProvider : ILoggerProvider + { + private readonly ITestOutputHelper _testOutputHelper; + private readonly LoggerExternalScopeProvider _scopeProvider = new LoggerExternalScopeProvider(); + + public XUnitLoggerProvider(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + public ILogger CreateLogger(string categoryName) + { + return new XUnitLogger(_testOutputHelper, _scopeProvider, categoryName); + } + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/test/WorkflowCore.IntegrationTests/Scenarios/DelayScenario.cs b/test/WorkflowCore.IntegrationTests/Scenarios/DelayScenario.cs index 704b27d79..e5402be0c 100644 --- a/test/WorkflowCore.IntegrationTests/Scenarios/DelayScenario.cs +++ b/test/WorkflowCore.IntegrationTests/Scenarios/DelayScenario.cs @@ -4,6 +4,7 @@ using Xunit; using FluentAssertions; using WorkflowCore.Testing; +using Xunit.Abstractions; namespace WorkflowCore.IntegrationTests.Scenarios { @@ -31,9 +32,9 @@ public class MyDataClass public class DelayScenario : WorkflowTest { - public DelayScenario() + public DelayScenario(ITestOutputHelper testOutputHelper) { - Setup(); + Setup(testOutputHelper); } [Fact] diff --git a/test/WorkflowCore.Tests.MongoDB/Scenarios/MongoDelayScenario.cs b/test/WorkflowCore.Tests.MongoDB/Scenarios/MongoDelayScenario.cs index 45aca549f..b5a1d572b 100644 --- a/test/WorkflowCore.Tests.MongoDB/Scenarios/MongoDelayScenario.cs +++ b/test/WorkflowCore.Tests.MongoDB/Scenarios/MongoDelayScenario.cs @@ -3,13 +3,14 @@ using MongoDB.Bson.Serialization; using WorkflowCore.IntegrationTests.Scenarios; using Xunit; +using Xunit.Abstractions; namespace WorkflowCore.Tests.MongoDB.Scenarios { [Collection("Mongo collection")] public class MongoDelayScenario : DelayScenario { - public MongoDelayScenario() : base() + public MongoDelayScenario(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { BsonClassMap.RegisterClassMap(map => map.AutoMap()); } diff --git a/test/WorkflowCore.Tests.MySQL/Scenarios/MysqlDelayScenario.cs b/test/WorkflowCore.Tests.MySQL/Scenarios/MysqlDelayScenario.cs index deed80f2b..68c247cf6 100644 --- a/test/WorkflowCore.Tests.MySQL/Scenarios/MysqlDelayScenario.cs +++ b/test/WorkflowCore.Tests.MySQL/Scenarios/MysqlDelayScenario.cs @@ -2,12 +2,17 @@ using System; using WorkflowCore.IntegrationTests.Scenarios; using Xunit; +using Xunit.Abstractions; namespace WorkflowCore.Tests.MySQL.Scenarios { [Collection("Mysql collection")] public class MysqlDelayScenario : DelayScenario { + public MysqlDelayScenario(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + protected override void ConfigureServices(IServiceCollection services) { services.AddWorkflow(cfg => diff --git a/test/WorkflowCore.Tests.Oracle/Scenarios/OracleDelayScenario.cs b/test/WorkflowCore.Tests.Oracle/Scenarios/OracleDelayScenario.cs index 55062f0c3..325106eb6 100644 --- a/test/WorkflowCore.Tests.Oracle/Scenarios/OracleDelayScenario.cs +++ b/test/WorkflowCore.Tests.Oracle/Scenarios/OracleDelayScenario.cs @@ -5,12 +5,17 @@ using WorkflowCore.Tests.Oracle; using Xunit; +using Xunit.Abstractions; namespace WorkflowCore.Tests.Oracle.Scenarios { [Collection("Oracle collection")] public class OracleDelayScenario : DelayScenario - { + { + public OracleDelayScenario(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + protected override void ConfigureServices(IServiceCollection services) { services.AddWorkflow(cfg => diff --git a/test/WorkflowCore.Tests.PostgreSQL/Scenarios/PostgresDelayScenario.cs b/test/WorkflowCore.Tests.PostgreSQL/Scenarios/PostgresDelayScenario.cs index 649632ac5..2d2814d07 100644 --- a/test/WorkflowCore.Tests.PostgreSQL/Scenarios/PostgresDelayScenario.cs +++ b/test/WorkflowCore.Tests.PostgreSQL/Scenarios/PostgresDelayScenario.cs @@ -2,12 +2,17 @@ using Microsoft.Extensions.DependencyInjection; using WorkflowCore.IntegrationTests.Scenarios; using Xunit; +using Xunit.Abstractions; namespace WorkflowCore.Tests.PostgreSQL.Scenarios { [Collection("Postgres collection")] public class PostgresDelayScenario : DelayScenario - { + { + public PostgresDelayScenario(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + protected override void ConfigureServices(IServiceCollection services) { services.AddWorkflow(cfg => diff --git a/test/WorkflowCore.Tests.SqlServer/Scenarios/SqlServerDelayScenario.cs b/test/WorkflowCore.Tests.SqlServer/Scenarios/SqlServerDelayScenario.cs index 5e623c1db..52b17fc6a 100644 --- a/test/WorkflowCore.Tests.SqlServer/Scenarios/SqlServerDelayScenario.cs +++ b/test/WorkflowCore.Tests.SqlServer/Scenarios/SqlServerDelayScenario.cs @@ -2,12 +2,17 @@ using Microsoft.Extensions.DependencyInjection; using WorkflowCore.IntegrationTests.Scenarios; using Xunit; +using Xunit.Abstractions; namespace WorkflowCore.Tests.SqlServer.Scenarios { [Collection("SqlServer collection")] public class SqlServerDelayScenario : DelayScenario - { + { + public SqlServerDelayScenario(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + protected override void ConfigureServices(IServiceCollection services) { services.AddWorkflow(cfg => diff --git a/test/WorkflowCore.Tests.Sqlite/Scenarios/SqliteDelayScenario.cs b/test/WorkflowCore.Tests.Sqlite/Scenarios/SqliteDelayScenario.cs new file mode 100644 index 000000000..f79dbd202 --- /dev/null +++ b/test/WorkflowCore.Tests.Sqlite/Scenarios/SqliteDelayScenario.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using WorkflowCore.IntegrationTests.Scenarios; +using Xunit; +using Xunit.Abstractions; + +namespace WorkflowCore.Tests.Sqlite.Scenarios +{ + [Collection("Sqlite collection")] + public class SqliteDelayScenario : DelayScenario + { + public SqliteDelayScenario(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + + protected override void ConfigureServices(IServiceCollection services) + { + services.AddWorkflow(cfg => + { + cfg.UseSqlite($"Data Source=wfc-tests-{DateTime.Now.Ticks}.db;", true); + cfg.UsePollInterval(TimeSpan.FromSeconds(2)); + }); + } + } +} +