Skip to content

Add testing docs: advanced scenarios and CI/CD patterns#456

Open
Copilot wants to merge 7 commits intomainfrom
copilot/update-testing-documentation-gaps
Open

Add testing docs: advanced scenarios and CI/CD patterns#456
Copilot wants to merge 7 commits intomainfrom
copilot/update-testing-documentation-gaps

Conversation

Copy link
Contributor

Copilot AI commented Feb 20, 2026

  • Create testing/advanced-scenarios.mdx - covers advanced DistributedApplicationTestingBuilder scenarios:
    • Selectively disabling/excluding resources in tests (WithExplicitStart, conditional resources)
    • Removing wait annotations in tests (verified compiles against Aspire.Hosting.Testing 13.1.1)
    • Environment variable overrides via WithEnvironment (verified compiles)
    • Refs to manage-app-host.mdx for argument passing and DistributedApplicationFactory (removed duplicate content)
    • File-based AppHost limitations: clearly documents that apphost.cs (no .csproj) cannot be tested with DistributedApplicationTestingBuilder — no project reference means no Projects namespace entry — with migration steps to convert to a project-based AppHost to enable testing
  • Create testing/testing-in-ci.mdx - covers CI/CD testing patterns:
    • Container runtime requirements (corrected macOS runner docs)
    • Timeout configuration to prevent hanging tests
    • Environment-aware timeouts (longer in CI)
    • Azure authentication in CI (service principal vs. developer identity)
    • Service principal environment variable configuration for GitHub Actions and Azure DevOps
    • Skip patterns for Azure tests when credentials are unavailable
    • Running tests in parallel with port randomization
    • Complete GitHub Actions workflow example
    • Troubleshooting common CI failures
  • Update sidebar (docs.topics.ts) with full locale translations for both new pages
  • Add syncKey="ci-provider" to <Tabs> in testing-in-ci.mdx
  • Add link to /whats-new/aspire-13/#defaultazurecredential-behavior-in-azure-deployments (PR Document AZURE_TOKEN_CREDENTIALS breaking change in Aspire 13.0 #424 content)
  • Update dotnet-version to '10.x' in GitHub Actions example
  • Fix app.ResourcesappHost.Resources (check on builder before BuildAsync)
  • Add AZURE_CLIENT_SECRET forwarding to CiAppHostFactory example
  • Fix Projects.MyApp_AppHostProjects.MyAppHost for consistency
  • Remove duplicated "Override configuration with AppHost arguments" and "DistributedApplicationFactory" sections (already in manage-app-host.mdx) — replaced with LearnMore cross-reference
  • Add using Aspire.Hosting.ApplicationModel; to WaitAnnotation code snippet
  • Verified WaitAnnotation removal code compiles against Aspire.Hosting.Testing 13.1.1
Original prompt

This section details on the original issue you should resolve

<issue_title>[Discord Feedback] Testing documentation gaps</issue_title>
<issue_description>## Summary

Based on analysis of 20,415 Discord messages + 147 #help threads (April 2025 - February 2026).

Question counts:

Topic Questions
Integration Testing 41
DistributedApplicationTestingBuilder 15+
Unit Testing 4

Docs That Exist

Slug Title Coverage
testing-overview Testing overview ✅ Basic setup
write-your-first-test Write your first test ✅ xUnit, NUnit, MSTest
manage-the-apphost-in-tests Manage the AppHost in tests ✅ DistributedApplicationTestingBuilder basics
access-resources-in-tests Access resources in tests ✅ Resource access patterns

Gaps in Existing Docs

1. Advanced DistributedApplicationTestingBuilder Scenarios

Customer Quotes:

"Does distributedapplicationtestingbuilder work with single file apphosts?"

"Can the DistributedApplicationTestingBuilder.CreateAsync<>() target an apphost that uses a file based app? Since the apphost then is not a project it naturally does not appear in the generated Projects namespace."

"How to override services/env vars in tests when services run in separate processes?"

From #help threads:

  • "How to exclude/disable certain resources during integration tests?"
  • "Removing WaitAnnotation in tests"

Action Items:

  • Single-file AppHost testing patterns
  • File-based AppHost with testing builder
  • Selectively disabling resources in tests
  • Cross-process service replacement
  • Environment variable overrides in tests

2. CI/CD Testing Patterns

Customer Quotes:

"Tests pass locally but fail in Azure DevOps because Cosmos uses principalType 'User' but CI uses Service Principal"

"I started some spikes for getting otel out of aspire tests in CI pipelines"

From #help threads:

  • Tests run indefinitely in GitHub Actions
  • principalType issues with Azure resources

Action Items:

  • Service Principal configuration for CI
  • Timeout handling in CI environments
  • OTEL extraction from tests for CI reporting
  • Running aspire CLI detached for E2E tests

3. Unit Testing Custom Publishers

From #help threads:

"Best practice for unit testing custom publisher/deployment?"

Action Items:

  • Testing custom publishers/deployers
  • Mocking publishing context

Data Source

  • Discord channels: #💫│general, #🔵│azure, #🔨│building-resources
  • Help threads: 147 from #🆘│help
  • Total messages: 20,415
  • Date range: April 2025 - February 2026
  • Verified against: aspire-list_docs and aspire-search_docs</issue_description>

<agent_instructions>Please address this issue, while using the .github/skills/doc-writer/SKILL.md. Be certain to also take into account, related issues, pull requests, and comments that are directly linked as well as comments.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Copilot AI changed the title [WIP] Update testing documentation to cover gaps Add testing docs: advanced scenarios and CI/CD patterns Feb 20, 2026
Copilot AI requested a review from IEvangelist February 20, 2026 20:53
Copy link
Member

@IEvangelist IEvangelist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR looks good so far, but let's double check it for accuracy by using the .github/skills/doc-tester/SKILL.md skill. Please also consider all new comments and feedback. @copilot

| `AZURE_TENANT_ID` | Your Azure Active Directory tenant ID |
| `AZURE_CLIENT_SECRET` | The client secret of your service principal |

<Tabs>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please always use a syncKey on all Tabs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added syncKey="ci-provider" to the <Tabs> component in da2ffdb.


### Use `DefaultAzureCredential` with environment variables

The recommended approach is to configure a service principal and set the standard Azure SDK environment variables in your CI pipeline. `DefaultAzureCredential` automatically picks up these environment variables:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to link to the new content that addressed this issue #424?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an <Aside type="note"> linking to DefaultAzureCredential behavior in Azure deployments (from PR #424) in da2ffdb. This surfaces the related AZURE_TOKEN_CREDENTIALS=managedidentity change for readers who may encounter it when their tests exercise deployment paths.

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.x'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dotnet-version: '9.x'
dotnet-version: '10.x'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to '10.x' in da2ffdb.

Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 21, 2026

This PR looks good so far, but let's double check it for accuracy by using the .github/skills/doc-tester/SKILL.md skill. Please also consider all new comments and feedback. @copilot

Ran doc-tester validation on both new pages. Two issues were found and fixed in da2ffdb:

  1. app.Resources was called on the built DistributedApplication — corrected to appHost.Resources (on the testing builder, before BuildAsync) to match the pattern used in existing docs.
  2. A dangling mention of "or the configureBuilder parameter" had no corresponding code example — removed the reference to avoid confusion.

Copilot AI requested a review from IEvangelist February 21, 2026 03:04
@IEvangelist IEvangelist marked this pull request as ready for review February 21, 2026 15:40
Copilot AI review requested due to automatic review settings February 21, 2026 15:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new Testing documentation pages to cover advanced DistributedApplicationTestingBuilder scenarios and CI/CD pipeline patterns, and wires them into the docs sidebar.

Changes:

  • Added a new “Advanced testing scenarios” page covering optional/conditional resources, wait annotation removal, env/config overrides, and DistributedApplicationFactory usage.
  • Added a new “Testing in CI/CD pipelines” page covering container runtime needs, timeout patterns, Azure auth in CI, parallelism/ports, and a GitHub Actions workflow example.
  • Updated the Testing sidebar section to include both new pages.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
src/frontend/src/content/docs/testing/testing-in-ci.mdx New CI/CD-focused testing guidance, examples, and troubleshooting.
src/frontend/src/content/docs/testing/advanced-scenarios.mdx New advanced testing patterns for Aspire integration tests.
src/frontend/config/sidebar/docs.topics.ts Adds the two new pages to the Testing section navigation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 160 to 174
// Read credentials from environment and forward to AppHost configuration
if (Environment.GetEnvironmentVariable("AZURE_CLIENT_ID") is { } clientId)
{
hostOptions.Configuration["AZURE_CLIENT_ID"] = clientId;
}

if (Environment.GetEnvironmentVariable("AZURE_TENANT_ID") is { } tenantId)
{
hostOptions.Configuration["AZURE_TENANT_ID"] = tenantId;
}

if (Environment.GetEnvironmentVariable("AZURE_SUBSCRIPTION_ID") is { } subscriptionId)
{
hostOptions.Configuration["AZURE_SUBSCRIPTION_ID"] = subscriptionId;
}
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This factory example forwards AZURE_CLIENT_ID/AZURE_TENANT_ID but omits AZURE_CLIENT_SECRET, even though the earlier section lists it as required for service principal auth. Add forwarding for AZURE_CLIENT_SECRET (and keep the set of forwarded variables consistent with the guidance above).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added AZURE_CLIENT_SECRET forwarding to the CiAppHostFactory example in c90d20c.

```csharp title="C# — IntegrationTest.cs"
// Works with top-level statement AppHosts
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyApp_AppHost>();
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within this article the AppHost type placeholder switches between Projects.MyAppHost and Projects.MyApp_AppHost. Using a single consistent placeholder name throughout will reduce confusion about the generated Projects.* type name format.

Suggested change
.CreateAsync<Projects.MyApp_AppHost>();
.CreateAsync<Projects.MyAppHost>();

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed Projects.MyApp_AppHostProjects.MyAppHost throughout the file in c90d20c.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Member

@IEvangelist IEvangelist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR looks good so far, but let's double check it for accuracy by using the .github/skills/doc-tester/SKILL.md skill. Please also consider all new comments and feedback/suggestions. @copilot

Comment on lines 155 to 217
### Override configuration with AppHost arguments

You can also pass arguments to the AppHost to override configuration values. Arguments are passed to the .NET configuration system, so they can override values from `appsettings.json`:

```csharp title="C# — IntegrationTest.cs"
[Fact]
public async Task TestWithCustomConfiguration()
{
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyAppHost>(
[
"--environment=Testing",
"MyApp:FeatureFlags:NewCheckout=true"
]);

await using var app = await appHost.BuildAsync();
await app.StartAsync();
}
```

### Override AppHost configuration using `DistributedApplicationFactory`

For more control over the AppHost configuration before any resources are created, use the `DistributedApplicationFactory` class and override the `OnBuilderCreating` lifecycle method:

```csharp title="C# — CustomAppHostFactory.cs"
public class CustomAppHostFactory()
: DistributedApplicationFactory(typeof(Projects.MyAppHost))
{
protected override void OnBuilderCreating(
DistributedApplicationOptions applicationOptions,
HostApplicationBuilderSettings hostOptions)
{
hostOptions.Configuration ??= new();

// Override configuration before the AppHost is created
hostOptions.Configuration["MyApp:ConnectionString"] = "Server=test-server;...";
hostOptions.Configuration["MyApp:FeatureFlags:NewCheckout"] = "true";
}
}
```

Use the factory in your test:

```csharp title="C# — IntegrationTest.cs"
[Fact]
public async Task TestWithCustomFactory()
{
await using var factory = new CustomAppHostFactory();
await using var app = await factory.BuildAsync();
await app.StartAsync();

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

using var httpClient = app.CreateHttpClient("api");
using var response = await httpClient.GetAsync("/");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
```

<LearnMore>
For more information about the `DistributedApplicationFactory` and its lifecycle methods, see [Manage the AppHost in tests](/testing/manage-app-host/).
</LearnMore>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two sections seem to already exist, see /testing/manage-app-host/. Perhaps they should be merged with the existing content.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the duplicate "Override configuration with AppHost arguments" and "Override AppHost configuration using DistributedApplicationFactory" sections in c90d20c. They're now replaced with short prose cross-references and a LearnMore pointing to /testing/manage-app-host/.

Comment on lines 95 to 127
### Remove wait annotations in tests

Resources in Aspire can have wait dependencies (via `WaitFor` or `WaitForCompletion`). In some tests, you may want to remove these wait annotations to speed up test startup or to test behavior when dependent resources are unavailable.

You can remove `WaitAnnotation` instances after building the testing builder, before calling `BuildAsync`:

```csharp title="C# — IntegrationTest.cs"
[Fact]
public async Task ApiStartsWithoutWaitingForDatabase()
{
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyAppHost>();

// Remove wait annotations from all resources so they start immediately
foreach (var resource in appHost.Resources)
{
var waitAnnotations = resource.Annotations.OfType<WaitAnnotation>().ToList();
foreach (var annotation in waitAnnotations)
{
resource.Annotations.Remove(annotation);
}
}

await using var app = await appHost.BuildAsync();
await app.StartAsync();

// Resources start without waiting for dependencies
}
```

<Aside type="note">
Removing wait annotations means resources start immediately, even if their dependencies aren't ready. Use this technique carefully—only when you intentionally want to test behavior in the absence of proper startup ordering.
</Aside>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you actually write temp code and run it, to verify that this works? Please create a temp directory (and delete it after you're done testing that this in fact works). Install the Aspire CLI and test it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — I created a temporary project against Aspire.Hosting.Testing 13.1.1 and verified the code compiles. Both WaitAnnotation (in Aspire.Hosting.ApplicationModel) and the resource.Annotations.Remove(annotation) call build successfully. I also added the missing using Aspire.Hosting.ApplicationModel; directive to the code snippet in c90d20c.

…amples, add AZURE_CLIENT_SECRET

Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 23, 2026

This PR looks good so far, but let's double check it for accuracy by using the .github/skills/doc-tester/SKILL.md skill. Please also consider all new comments and feedback/suggestions. @copilot

Ran doc-tester on both updated pages — all checks pass. The one gap it found (missing using Aspire.Hosting.ApplicationModel; in the WaitAnnotation snippet) has been fixed in c90d20c.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • centralus-2.in.applicationinsights.azure.com
    • Triggering command: /home/REDACTED/.aspire/bin/aspire /home/REDACTED/.aspire/bin/aspire config set -g channel staging (dns block)
    • Triggering command: /home/REDACTED/.aspire/bin/aspire aspire new aspire-starter -n WaitTest -o . (dns block)
    • Triggering command: /home/REDACTED/.aspire/bin/aspire aspire new --list (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Comment on lines 169 to 202
## Single-file and minimal AppHost considerations

The `DistributedApplicationTestingBuilder.CreateAsync<T>()` method uses a project reference (from the `Projects` namespace) to locate and start your AppHost. This means your AppHost must be a **project** referenced in your test project.

<Aside type="note">
File-based or single-file AppHosts that aren't structured as .NET projects can't be directly targeted by `DistributedApplicationTestingBuilder.CreateAsync<T>()`. The generic type parameter `T` must be a type from the auto-generated `Projects` namespace, which is only available for project references.
</Aside>

If your AppHost uses top-level statements (a common pattern in minimal or single-file AppHosts), it works fine as long as it's a project. Top-level statement projects still produce the necessary project reference metadata:

```csharp title="C# — AppHost.cs (top-level statements)"
// Top-level statements work fine—this is still a project
var builder = DistributedApplication.CreateBuilder(args);

builder.AddProject<Projects.Api>("api");

builder.Build().Run();
```

This AppHost works with the testing builder the same as a class-based AppHost:

```csharp title="C# — IntegrationTest.cs"
// Works with top-level statement AppHosts
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyAppHost>();
```

The `Projects` namespace entries are generated based on the `<ProjectReference>` elements in your test project file. Ensure your AppHost project is referenced:

```xml title="XML — MyApp.Tests.csproj"
<ItemGroup>
<ProjectReference Include="..\MyApp.AppHost\MyApp.AppHost.csproj" />
</ItemGroup>
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire section needs to be updated to say that C# file-based apps (including apphost.cs) cannot be referenced by test projects. Therefore, you cannot test file-based apps in aspire.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot - please have a look at this previous comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrote the section in bc796d3. It now leads with a <Aside type="caution"> clearly stating that file-based AppHosts (apphost.cs without a .csproj) cannot be tested with DistributedApplicationTestingBuilder, explains why (no project reference → not in Projects namespace), and includes migration steps to convert a file-based AppHost to a standard .csproj project to enable testing.

Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
Removed migration steps for file-based AppHost to project structure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Discord Feedback] Testing documentation gaps

3 participants