Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .nuget/Codebelt.Extensions.Xunit.App/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## About

An open-source project (MIT license) that targets and complements the [xUnit.net](https://xunit.net/) test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.
An open-source project (MIT license) that targets and complements the xUnit.net test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.

It is, by heart, free, flexible and built to extend and boost your agile codebelt.

## **Codebelt.Extensions.Xunit.App** for .NET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Availability: .NET 9 and .NET 8
- CHANGED Dependencies to latest and greatest with respect to TFMs
- REMOVED Support for TFM .NET 6 (LTS)

# Bug Fixes
- FIXED AspNetCoreHostFixture class in the Codebelt.Extensions.Xunit.Hosting.AspNetCore namespace to preserve ExecutionContext and AsyncLocal{T} values from the client to the server (vital for ITestOutputHelperAccessor combined with xUnit test logging when using HttpClient)

Version 8.4.0
Availability: .NET 8 and .NET 6

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## About

An open-source project (MIT license) that targets and complements the [xUnit.net](https://xunit.net/) test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.
An open-source project (MIT license) that targets and complements the xUnit.net test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.

Perhaps even more convenient than what [WebApplicationFactory](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.testing.webapplicationfactory-1) has to offer?

It is, by heart, free, flexible and built to extend and boost your agile codebelt.

## **Codebelt.Extensions.Xunit.Hosting.AspNetCore** for .NET
Expand Down
14 changes: 13 additions & 1 deletion .nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0
- CHANGED Dependencies to latest and greatest with respect to TFMs
- REMOVED Support for TFM .NET 6 (LTS)

Version 8.4.1
Availability: .NET 8, .NET 6 and .NET Standard 2.0

# ALM
- CHANGED Dependencies to latest and greatest with respect to TFMs

# Breaking Changes
- RENAMED AddXunitTestOutputHelperAccessor and AddXunitTestOutputHelperAccessor{T} on the ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace to AddXunitTestLoggingOutputHelperAccessor and AddXunitTestLoggingOutputHelperAccessor{T} (for consistency)

# New Features
- EXTENDED ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace with one new extension method for the IServiceCollection interface: An overload of AddXunitTestLogging

Version 8.4.0
Availability: .NET 8, .NET 6 and .NET Standard 2.0

Expand All @@ -13,7 +25,7 @@ Availability: .NET 8, .NET 6 and .NET Standard 2.0

# New Features
- ADDED ServiceProviderExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace that consist of one extension method for the IServiceProvider interface: GetRequiredScopedService
- EXTENDED ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace with three new extension methods for the IServiceCollection interface: AddXunitTestOutputHelperAccessor and AddXunitTestOutputHelperAccessor{T}
- EXTENDED ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace with two new extension methods for the IServiceCollection interface: AddXunitTestOutputHelperAccessor and AddXunitTestOutputHelperAccessor{T}

Version 8.3.2
Availability: .NET 8, .NET 6 and .NET Standard 2.0
Expand Down
5 changes: 3 additions & 2 deletions .nuget/Codebelt.Extensions.Xunit.Hosting/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## About

An open-source project (MIT license) that targets and complements the [xUnit.net](https://xunit.net/) test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.
An open-source project (MIT license) that targets and complements the xUnit.net test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.

It is, by heart, free, flexible and built to extend and boost your agile codebelt.

## **Codebelt.Extensions.Xunit.Hosting** for .NET
Expand Down Expand Up @@ -37,7 +38,7 @@ public class AspNetCoreHostTestTest : AspNetCoreHostTest<AspNetCoreHostFixture>

public override void ConfigureServices(IServiceCollection services)
{
services.AddXunitTestOutputHelperAccessor();
services.AddXunitTestLoggingOutputHelperAccessor();
services.AddXunitTestLogging(new TestOutputHelperAccessor(TestOutput));
}
}
Expand Down
3 changes: 2 additions & 1 deletion .nuget/Codebelt.Extensions.Xunit/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## About

An open-source project (MIT license) that targets and complements the [xUnit.net](https://xunit.net/) test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.
An open-source project (MIT license) that targets and complements the xUnit.net test platform. It provides a uniform and convenient way of doing unit test for all project types in .NET.

It is, by heart, free, flexible and built to extend and boost your agile codebelt.

## **Codebelt.Extensions.Xunit** for .NET
Expand Down
23 changes: 22 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba

This major release is first and foremost focused on ironing out any wrinkles that have been introduced with .NET 9 preview releases so the final release is production ready together with the official launch from Microsoft.

### Fixed

- AspNetCoreHostFixture class in the Codebelt.Extensions.Xunit.Hosting.AspNetCore namespace to preserve ExecutionContext and AsyncLocal{T} values from the client to the server (vital for ITestOutputHelperAccessor combined with xUnit test logging when using HttpClient)
- Prior to this release, you can override `ConfigureHost` on your `AspNetCoreHostTest` implementation and apply this code:
```csharp
protected override void ConfigureHost(IHostBuilder hb)
{
hb.ConfigureWebHost(builder => builder.UseTestServer(o => o.PreserveExecutionContext = true));
}
```

## [8.4.1] - 2024-09-16

### Added

- ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace received one new extension method for the IServiceCollection interface: An overload of AddXunitTestLogging

### Changed

- AddXunitTestOutputHelperAccessor and AddXunitTestOutputHelperAccessor{T} on the ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace was renamed to AddXunitTestLoggingOutputHelperAccessor and AddXunitTestLoggingOutputHelperAccessor{T} (for consistency)

## [8.4.0] - 2024-09-15

### Added
Expand All @@ -19,7 +40,7 @@ This major release is first and foremost focused on ironing out any wrinkles tha
- ITestOutputHelperAccessor interface in the Codebelt.Extensions.Xunit namespace that provides access to the ITestOutputHelper instance
- TestOutputHelperAccessor class in the Codebelt.Extensions.Xunit namespace that provides a default implementation of the ITestOutputHelper interface
- ServiceProviderExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace that consist of one extension method for the IServiceProvider interface: GetRequiredScopedService
- ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace was extended with three new extension methods for the IServiceCollection interface: AddXunitTestOutputHelperAccessor and AddXunitTestOutputHelperAccessor{T}
- ServiceCollectionExtensions class in the Codebelt.Extensions.Xunit.Hosting namespace received two new extension methods for the IServiceCollection interface: AddXunitTestOutputHelperAccessor and AddXunitTestOutputHelperAccessor{T}

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public override void ConfigureHost(Test hostTest)
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.UseTestServer(o => o.PreserveExecutionContext = true)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseEnvironment("Development")
.ConfigureAppConfiguration((context, config) =>
Expand Down Expand Up @@ -82,16 +82,19 @@ public override void ConfigureHost(Test hostTest)
.UseSetting(HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name);
});

ConfigureHostCallback(hb);

hb.UseDefaultServiceProvider(o =>
{
o.ValidateOnBuild = true;
o.ValidateScopes = true;
});

ConfigureHostCallback(hb);

var host = hb.Build();
Task.Run(() => host.StartAsync()).GetAwaiter().GetResult();
Task.Run(() => host.StartAsync().ConfigureAwait(false))
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
Host = host;
}

Expand Down
4 changes: 3 additions & 1 deletion src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Collections;
using System.Linq;
using Cuemon;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit.Abstractions;

namespace Codebelt.Extensions.Xunit.Hosting
{
Expand All @@ -12,7 +14,7 @@ namespace Codebelt.Extensions.Xunit.Hosting
public static class LoggerExtensions
{
/// <summary>
/// Returns the associated <see cref="ITestStore{T}"/> that is provided when settings up services from <see cref="ServiceCollectionExtensions.AddXunitTestLogging"/>.
/// Returns the associated <see cref="ITestStore{T}"/> that is provided when settings up services from either <see cref="ServiceCollectionExtensions.AddXunitTestLogging(IServiceCollection,ITestOutputHelper,LogLevel)"/> or <see cref="ServiceCollectionExtensions.AddXunitTestLogging(IServiceCollection,ITestOutputHelperAccessor,LogLevel)"/>.
/// </summary>
/// <param name="logger">The <see cref="ILogger{TCategoryName}"/> from which to retrieve the <see cref="ITestStore{T}"/>.</param>
/// <returns>Returns an implementation of <see cref="ITestStore{T}"/> with all logged entries expressed as <see cref="XunitTestLoggerEntry"/>.</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,60 @@ namespace Codebelt.Extensions.Xunit.Hosting
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds a unit test optimized implementation of output logging to the <paramref name="services"/> collection.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to extend.</param>
/// <param name="output">The <see cref="ITestOutputHelper"/> that provides the output for the logging.</param>
/// <param name="minimumLevel">The <see cref="LogLevel"/> that specifies the minimum level to include for the logging.</param>
/// <returns>A reference to <paramref name="services" /> so that additional configuration calls can be chained.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="services"/> cannot be null -or-
/// <paramref name="output"/> cannot be null.
/// </exception>
public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, ITestOutputHelper output, LogLevel minimumLevel = LogLevel.Trace)
{
Validator.ThrowIfNull(services);
Validator.ThrowIfNull(output);
services.AddLogging(builder =>
{
builder.SetMinimumLevel(minimumLevel);
builder.AddProvider(new XunitTestLoggerProvider(output));
});
return services;
}
/// <summary>
/// Adds a unit test optimized implementation of output logging to the <paramref name="services"/> collection.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to extend.</param>
/// <param name="output">The <see cref="ITestOutputHelper"/> that provides the output for the logging.</param>
/// <param name="minimumLevel">The <see cref="LogLevel"/> that specifies the minimum level to include for the logging.</param>
/// <returns>A reference to <paramref name="services" /> so that additional configuration calls can be chained.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="services"/> cannot be null -or-
/// <paramref name="output"/> cannot be null.
/// </exception>
public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, ITestOutputHelper output, LogLevel minimumLevel = LogLevel.Trace)
{
Validator.ThrowIfNull(services);
Validator.ThrowIfNull(output);
services.AddLogging(builder =>
{
builder.SetMinimumLevel(minimumLevel);
builder.AddProvider(new XunitTestLoggerProvider(output));
});
return services;
}

/// <summary>
/// Adds a unit test optimized implementation of output logging to the <paramref name="services"/> collection.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to extend.</param>
/// <param name="accessor">The <see cref="ITestOutputHelperAccessor"/> that provides access to the output for the logging.</param>
/// <param name="minimumLevel">The <see cref="LogLevel"/> that specifies the minimum level to include for the logging.</param>
/// <returns>A reference to <paramref name="services" /> so that additional configuration calls can be chained.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="services"/> cannot be null -or-
/// <paramref name="accessor"/> cannot be null.
/// </exception>
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;
}

/// <summary>
/// Adds a default implementation of <see cref="ITestOutputHelperAccessor"/> to the <paramref name="services"/> collection.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to extend.</param>
/// <returns>A reference to <paramref name="services" /> so that additional configuration calls can be chained.</returns>
public static IServiceCollection AddXunitTestOutputHelperAccessor(this IServiceCollection services)
public static IServiceCollection AddXunitTestLoggingOutputHelperAccessor(this IServiceCollection services)
{
services.AddXunitTestOutputHelperAccessor<TestOutputHelperAccessor>();
services.AddXunitTestLoggingOutputHelperAccessor<TestOutputHelperAccessor>();
return services;
}

Expand All @@ -54,7 +77,7 @@ public static IServiceCollection AddXunitTestOutputHelperAccessor(this IServiceC
/// <exception cref="ArgumentNullException">
/// <paramref name="services"/> cannot be null.
/// </exception>
public static IServiceCollection AddXunitTestOutputHelperAccessor<T>(this IServiceCollection services) where T : class, ITestOutputHelperAccessor
public static IServiceCollection AddXunitTestLoggingOutputHelperAccessor<T>(this IServiceCollection services) where T : class, ITestOutputHelperAccessor
{
Validator.ThrowIfNull(services);
services.AddSingleton<ITestOutputHelperAccessor, T>();
Expand Down
1 change: 1 addition & 0 deletions src/Codebelt.Extensions.Xunit.Hosting/XunitTestLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
var message = builder.ToString();
if (_accessor != null)
{
if (_accessor.TestOutput == null) { throw new InvalidOperationException($"{nameof(ITestOutputHelperAccessor)}.{nameof(ITestOutputHelperAccessor.TestOutput)} is null."); }
_accessor.TestOutput.WriteLine(message);
}
else
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets;
using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http;
Expand Down Expand Up @@ -34,6 +35,9 @@ public async Task ShouldHaveResultOfBoolMiddlewareInBody()

Assert.Equal("Hello awesome developers!", context!.Response.Body.ToEncodedString(o => o.LeaveOpen = true));

var logger = _pipeline.ApplicationServices.GetRequiredService<ILogger<AspNetCoreHostTestTest>>();
logger.LogInformation("Hello from {0}", nameof(ShouldHaveResultOfBoolMiddlewareInBody));

await pipeline(context);

Assert.Equal("A:True, B:False, C:True, D:False, E:True, F:False", context.Response.Body.ToEncodedString());
Expand All @@ -51,6 +55,11 @@ public void ShouldLogToXunitTestLogging()
{
var logger = _pipeline.ApplicationServices.GetRequiredService<ILogger<AspNetCoreHostTestTest>>();
logger.LogInformation("Hello from {0}", nameof(ShouldLogToXunitTestLogging));
var store = _pipeline.ApplicationServices.GetRequiredService<ILogger<AspNetCoreHostTestTest>>().GetTestStore();
var entry = store.Query(entry => entry.Message.Contains("Hello from", StringComparison.OrdinalIgnoreCase)).SingleOrDefault();

Assert.NotNull(entry);
Assert.Equal("Information: Hello from ShouldLogToXunitTestLogging", entry.Message);
}

public override void ConfigureApplication(IApplicationBuilder app)
Expand All @@ -68,8 +77,8 @@ public override void ConfigureServices(IServiceCollection services)
o.C = true;
o.E = true;
});
services.AddXunitTestOutputHelperAccessor();
services.AddXunitTestLogging(TestOutput);
services.AddXunitTestLoggingOutputHelperAccessor();
services.AddXunitTestLogging(new TestOutputHelperAccessor(TestOutput));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Mvc;

namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets
{
[ApiController]
[Route("[controller]")]
public class FakeController : ControllerBase
{
public FakeController()
{
}

[HttpGet]
public IActionResult Get()
{
return Ok("Unit Test");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<ItemGroup>
<PackageReference Include="Cuemon.AspNetCore" Version="9.0.0-preview.5" />
<PackageReference Include="Cuemon.Extensions.AspNetCore" Version="9.0.0-preview.5" />
<PackageReference Include="Cuemon.Extensions.IO" Version="9.0.0-preview.5" />
</ItemGroup>

Expand Down
Loading