![]() |
VOOZH | about |
dotnet add package NetEvolve.Logging.XUnit --version 2.0.193
NuGet\Install-Package NetEvolve.Logging.XUnit -Version 2.0.193
<PackageReference Include="NetEvolve.Logging.XUnit" Version="2.0.193" />
<PackageVersion Include="NetEvolve.Logging.XUnit" Version="2.0.193" />Directory.Packages.props
<PackageReference Include="NetEvolve.Logging.XUnit" />Project file
paket add NetEvolve.Logging.XUnit --version 2.0.193
#r "nuget: NetEvolve.Logging.XUnit, 2.0.193"
#:package NetEvolve.Logging.XUnit@2.0.193
#addin nuget:?package=NetEvolve.Logging.XUnit&version=2.0.193Install as a Cake Addin
#tool nuget:?package=NetEvolve.Logging.XUnit&version=2.0.193Install as a Cake Tool
A powerful logging implementation for xUnit.net that enables you to capture, inspect, and assert on log messages generated during test execution. Perfect for debugging tests, verifying logging behavior, and building testable applications with comprehensive logging coverage.
Microsoft.Extensions.Logging integration - Works seamlessly with the standard .NET logging infrastructureILoggingBuilderTimeProvider support - Testable time-based logging scenariosITestOutputHelper and IMessageSinkXUnitLogger<T>dotnet add package NetEvolve.Logging.XUnit
Or via the NuGet Package Manager:
Install-Package NetEvolve.Logging.XUnit
ITestOutputHelperusing Microsoft.Extensions.Logging;
using NetEvolve.Logging.XUnit;
using Xunit;
using Xunit.Abstractions;
public class ExampleTests
{
private readonly ITestOutputHelper _output;
public ExampleTests(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void BasicLoggingExample()
{
// Create a logger
var logger = XUnitLogger.CreateLogger<ExampleTests>(_output);
// Use the logger
logger.LogInformation("Starting test execution");
logger.LogDebug("Debug information: {Value}", 42);
// Perform test logic
var result = 2 + 2;
logger.LogInformation("Calculation result: {Result}", result);
// Assert on log messages
Assert.NotEmpty(logger.LoggedMessages);
Assert.Contains(logger.LoggedMessages, m => m.Message.Contains("Starting test"));
}
}
Create loggers directly using the static factory methods:
// Generic typed logger
var logger = XUnitLogger.CreateLogger<MyClass>(_output);
// Non-generic logger
var logger = XUnitLogger.CreateLogger(_output);
// With custom options
var options = new XUnitLoggerOptions
{
TimestampFormat = "HH:mm:ss.fff",
DisableScopes = false
};
var logger = XUnitLogger.CreateLogger<MyClass>(_output, options: options);
// With custom TimeProvider (for testing)
var timeProvider = new FakeTimeProvider();
var logger = XUnitLogger.CreateLogger<MyClass>(_output, timeProvider, options: options);
Use the AddXUnit extension method with ILoggingBuilder:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NetEvolve.Logging.XUnit;
using Xunit;
using Xunit.Abstractions;
public class ServiceTests
{
private readonly ITestOutputHelper _output;
public ServiceTests(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void TestWithDependencyInjection()
{
// Configure services with xUnit logging
var services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddXUnit(_output, new XUnitLoggerOptions
{
TimestampFormat = "HH:mm:ss.fff"
});
});
// Add your services
services.AddTransient<MyService>();
// Build and use
var serviceProvider = services.BuildServiceProvider();
var service = serviceProvider.GetRequiredService<MyService>();
// Your service will now log to xUnit output
service.DoSomething();
}
}
IMessageSink (xUnit v3)For xUnit v3 scenarios where ITestOutputHelper isn't available:
using NetEvolve.Logging.XUnit;
using Xunit.Sdk;
public class FrameworkTests
{
private readonly IMessageSink _messageSink;
public FrameworkTests(IMessageSink messageSink)
{
_messageSink = messageSink;
}
[Fact]
public void TestWithMessageSink()
{
var logger = XUnitLogger.CreateLogger(_messageSink);
logger.LogInformation("This will be written to the message sink");
}
}
Customize logger behavior using XUnitLoggerOptions:
var options = new XUnitLoggerOptions
{
// Timestamp format (default: "o" - ISO 8601)
TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff",
// Disable timestamp output (default: false)
DisableTimestamp = false,
// Disable log level output (default: false)
DisableLogLevel = false,
// Disable scope information (default: false)
DisableScopes = false,
// Disable additional structured data (default: false)
DisableAdditionalInformation = false
};
var logger = XUnitLogger.CreateLogger<MyClass>(_output, options: options);
Default output:
2025-11-26T10:30:45.123+00:00 [INFO] User logged in successfully
UserId: 123
Username: john.doe
Minimal output (all optional features disabled):
User logged in successfully
Custom timestamp format:
10:30:45.123 [INFO] User logged in successfully
The logger captures all messages for inspection and assertions:
[Fact]
public void VerifyLoggingBehavior()
{
var logger = XUnitLogger.CreateLogger<MyClass>(_output);
// Perform operations that generate logs
logger.LogInformation("Operation started");
logger.LogWarning("Potential issue detected");
logger.LogError("Operation failed");
// Access all logged messages
var messages = logger.LoggedMessages;
// Assertions
Assert.Equal(3, messages.Count);
Assert.Contains(messages, m => m.LogLevel == LogLevel.Information);
Assert.Contains(messages, m => m.LogLevel == LogLevel.Warning);
Assert.Contains(messages, m => m.LogLevel == LogLevel.Error);
Assert.Contains(messages, m => m.Message.Contains("Operation started"));
// Check timestamps
Assert.All(messages, m => Assert.True(m.Timestamp != default));
// Check for exceptions
var errorMessage = messages.First(m => m.LogLevel == LogLevel.Error);
Assert.Null(errorMessage.Exception); // or Assert.NotNull if exception was logged
}
[Fact]
public void TestWithScopes()
{
var logger = XUnitLogger.CreateLogger<MyClass>(_output);
using (logger.BeginScope("Operation {OperationId}", "12345"))
{
logger.LogInformation("Processing started");
using (logger.BeginScope("Step {StepNumber}", 1))
{
logger.LogDebug("Step 1 execution");
}
logger.LogInformation("Processing completed");
}
// Verify scope information was captured
var messages = logger.LoggedMessages;
Assert.All(messages, m => Assert.NotEmpty(m.Scopes));
}
[Fact]
public void TestWithFakeTimeProvider()
{
var fakeTime = new FakeTimeProvider();
fakeTime.SetUtcNow(new DateTimeOffset(2025, 1, 1, 12, 0, 0, TimeSpan.Zero));
var logger = XUnitLogger.CreateLogger<MyClass>(_output, fakeTime);
logger.LogInformation("First message");
// Advance time
fakeTime.Advance(TimeSpan.FromMinutes(5));
logger.LogInformation("Second message");
// Verify timestamps
var messages = logger.LoggedMessages;
Assert.Equal(5, (messages[1].Timestamp - messages[0].Timestamp).TotalMinutes);
}
public class IntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
private readonly ITestOutputHelper _output;
public IntegrationTests(WebApplicationFactory<Program> factory, ITestOutputHelper output)
{
_factory = factory;
_output = output;
}
[Fact]
public async Task ApiEndpoint_LogsRequestDetails()
{
// Create a custom web application factory with xUnit logging
var factory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddXUnit(_output);
logging.SetMinimumLevel(LogLevel.Debug);
});
});
var client = factory.CreateClient();
// Make request
var response = await client.GetAsync("/api/users");
// All logging from the API will appear in test output
Assert.True(response.IsSuccessStatusCode);
}
}
CreateLogger<T>() provides better categorizationLoggedMessages - Validate logging behavior as part of your testsXUnitLoggerOptionsEnsure you're passing the correct ITestOutputHelper instance:
public class MyTests
{
private readonly ITestOutputHelper _output;
// Constructor injection
public MyTests(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void TestMethod()
{
// Use the injected instance
var logger = XUnitLogger.CreateLogger<MyTests>(_output);
logger.LogInformation("This will appear in test output");
}
}
This occurs when trying to write to ITestOutputHelper outside test execution. Ensure logging only happens during test execution, not in class constructors or after test completion.
Microsoft.Extensions.Logging abstractionsThis project is licensed under the MIT License - see the file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on NetEvolve.Logging.XUnit:
| Package | Downloads |
|---|---|
|
NetEvolve.Logging.Measurement
Extensions for `ILogger` implementations to measure execution times for a named scope. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.193 | 400 | 4/1/2026 |
| 2.0.166 | 194 | 3/24/2026 |
| 2.0.102 | 382 | 1/14/2026 |
| 2.0.60 | 188 | 12/31/2025 |
| 2.0.10 | 419 | 11/26/2025 |
| 1.3.94 | 848 | 5/9/2025 |
| 1.3.54 | 468 | 2/2/2025 |
| 1.3.50 | 758 | 1/29/2025 |
| 1.3.24 | 513 | 1/1/2025 |
| 1.3.1 | 500 | 12/3/2024 |
| 1.2.65 | 1,228 | 9/11/2024 |
| 1.2.47 | 329 | 8/26/2024 |
| 1.1.14 | 1,197 | 5/30/2024 |
| 1.1.2 | 464 | 5/23/2024 |
| 1.0.0 | 267 | 5/21/2024 |