Skip to content

Clarify how to capture logs from tests in .NET Aspire documentation #4252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.4.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.7" />
<PackageReference Include="MSTest" Version="3.10.1" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Microsoft.Extensions.Logging;

namespace AspireApp.Tests;

[TestClass]
public class LoggingTest
{
[TestMethod]
public async Task GetWebResourceRootReturnsOkStatusCodeWithLogging()
{
// Arrange
var builder = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();

builder.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});

// Configure logging to capture test execution logs
builder.Services.AddLogging(logging => logging
.AddConsole() // Outputs logs to console
.AddFilter("Default", LogLevel.Information)
.AddFilter("Microsoft.AspNetCore", LogLevel.Warning)
.AddFilter("Aspire.Hosting.Dcp", LogLevel.Warning));

await using var app = await builder.BuildAsync();

await app.StartAsync();

// Act
var httpClient = app.CreateHttpClient("webfrontend");

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await app.ResourceNotifications.WaitForResourceHealthyAsync(
"webfrontend",
cts.Token);

var response = await httpClient.GetAsync("/");

// Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.4.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="NUnit" Version="4.3.2" />
<PackageReference Include="NUnit.Analyzers" Version="4.9.2" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.Extensions.Logging;

namespace AspireApp.Tests;

public class LoggingTest
{
[Test]
public async Task GetWebResourceRootReturnsOkStatusCodeWithLogging()
{
// Arrange
var builder = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();

builder.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});

// Configure logging to capture test execution logs
builder.Services.AddLogging(logging => logging
.AddConsole() // Outputs logs to console
.AddFilter("Default", LogLevel.Information)
.AddFilter("Microsoft.AspNetCore", LogLevel.Warning)
.AddFilter("Aspire.Hosting.Dcp", LogLevel.Warning));

await using var app = await builder.BuildAsync();

await app.StartAsync();

// Act
var httpClient = app.CreateHttpClient("webfrontend");

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await app.ResourceNotifications.WaitForResourceHealthyAsync(
"webfrontend",
cts.Token);

var response = await httpClient.GetAsync("/");

// Assert
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.4.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public async Task GetWebResourceRootReturnsOkStatusCode()
clientBuilder.AddStandardResilienceHandler();
});

// To output logs to the xUnit.net ITestOutputHelper,
// consider adding a package from https://www.nuget.org/packages?q=xunit+logging
// To capture logs from your tests, see the "Capture logs from tests" section
// in the documentation or refer to LoggingTest.cs for a complete example

await using var app = await builder.BuildAsync();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.Extensions.Logging;

namespace AspireApp.Tests;

public class LoggingTest
{
[Fact]
public async Task GetWebResourceRootReturnsOkStatusCodeWithLogging()
{
// Arrange
var builder = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();

builder.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});

// Configure logging to capture test execution logs
builder.Services.AddLogging(logging => logging
.AddConsole() // Outputs logs to console
.AddFilter("Default", LogLevel.Information)
.AddFilter("Microsoft.AspNetCore", LogLevel.Warning)
.AddFilter("Aspire.Hosting.Dcp", LogLevel.Warning));

await using var app = await builder.BuildAsync();

await app.StartAsync();

// Act
var httpClient = app.CreateHttpClient("webfrontend");

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await app.ResourceNotifications.WaitForResourceHealthyAsync(
"webfrontend",
cts.Token);

var response = await httpClient.GetAsync("/");

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
73 changes: 73 additions & 0 deletions docs/testing/write-your-first-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,79 @@ The .NET Aspire testing project template makes it easier to create test projects

Finally, when using the `DistributedApplicationTestingBuilder` all resource logs are redirected to the `DistributedApplication` by default. The redirection of resource logs enables scenarios where you want to assert that a resource is logging correctly.

## Capture logs from tests

When writing tests for your .NET Aspire applications, you might want to capture and view logs to help with debugging and monitoring test execution. The `DistributedApplicationTestingBuilder` provides access to the service collection, allowing you to configure logging for your test scenarios.

### Configure logging providers

To capture logs from your tests, use the `AddLogging` method on the `builder.Services` to configure logging providers specific to your testing framework:

:::zone pivot="xunit"

:::code language="csharp" source="snippets/testing/xunit/AspireApp.Tests/LoggingTest.cs":::

:::zone-end
:::zone pivot="mstest"

:::code language="csharp" source="snippets/testing/mstest/AspireApp.Tests/LoggingTest.cs":::

:::zone-end
:::zone pivot="nunit"

:::code language="csharp" source="snippets/testing/nunit/AspireApp.Tests/LoggingTest.cs":::

:::zone-end

### Configure log filters

Since the `appsettings.json` configuration from your application under test isn't automatically replicated in test projects, you need to explicitly configure log filters. This is important to avoid excessive logging from infrastructure components that might overwhelm your test output:

```csharp
builder.Services.AddLogging(logging => logging
.AddFilter("Default", LogLevel.Information)
.AddFilter("Microsoft.AspNetCore", LogLevel.Warning)
.AddFilter("Aspire.Hosting.Dcp", LogLevel.Warning));
```

The preceding configuration:

- Sets the default log level to `Information` for most application logs.
- Reduces noise from ASP.NET Core infrastructure by setting it to `Warning` level.
- Limits Aspire hosting infrastructure logs to `Warning` level to focus on application-specific logs.

### Popular logging packages

Different testing frameworks have different logging provider packages available:

:::zone pivot="xunit"

For xUnit, consider using one of these logging packages:

- [📦 Xunit.DependencyInjection.Logging](https://www.nuget.org/packages/Xunit.DependencyInjection.Logging) - Integrates with xUnit's dependency injection
- [📦 Serilog.Extensions.Logging.File](https://www.nuget.org/packages/Serilog.Extensions.Logging.File) - Writes logs to files
- [📦 Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Console) - Outputs logs to console

:::zone-end
:::zone pivot="mstest"

For MSTest, consider using one of these logging packages:

- [📦 Extensions.Logging.MSTest](https://www.nuget.org/packages/Extensions.Logging.MSTest) - Integrates with MSTest framework
- [📦 Serilog.Extensions.Logging.File](https://www.nuget.org/packages/Serilog.Extensions.Logging.File) - Writes logs to files
- [📦 Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Console) - Outputs logs to console

:::zone-end
:::zone pivot="nunit"

For NUnit, consider using one of these logging packages:

- [📦 Extensions.Logging.NUnit](https://www.nuget.org/packages/Extensions.Logging.NUnit) - Integrates with NUnit framework
- [📦 Serilog.Extensions.Logging.File](https://www.nuget.org/packages/Serilog.Extensions.Logging.File) - Writes logs to files
- [📦 Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Console) - Outputs logs to console

:::zone-end

## See also

- [Unit testing C# in .NET using dotnet test and xUnit](/dotnet/core/testing/unit-testing-with-dotnet-test)
Expand Down
Loading