TestFramework.Container.Azure
0.4.0
dotnet add package TestFramework.Container.Azure --version 0.4.0
NuGet\Install-Package TestFramework.Container.Azure -Version 0.4.0
<PackageReference Include="TestFramework.Container.Azure" Version="0.4.0" />
<PackageVersion Include="TestFramework.Container.Azure" Version="0.4.0" />
<PackageReference Include="TestFramework.Container.Azure" />
paket add TestFramework.Container.Azure --version 0.4.0
#r "nuget: TestFramework.Container.Azure, 0.4.0"
#:package TestFramework.Container.Azure@0.4.0
#addin nuget:?package=TestFramework.Container.Azure&version=0.4.0
#tool nuget:?package=TestFramework.Container.Azure&version=0.4.0
TestFramework.Container.Azure
TestFramework.Container.Azure lets a normal TestFramework Azure timeline run against Docker-backed emulator infrastructure.
Use it when you want to keep the normal TestFramework.Azure timeline shape, but you want Blob, Table, Cosmos, SQL Server, or Service Bus dependencies to come from local containers instead of a live Azure environment.
Important limitation: Logic Apps are not supported in container mode. For Logic App tests, use TestFramework.Azure with live Azure-hosted workflows instead.
Pick The Smallest Starting Point
Choose the entry path that matches how much infrastructure shape you already know.
- Existing Azure timeline, explicit component graph: use
DockerAzureEnvironment.For<TRootDefinition>(). - One local Function App plus common bindings: use the additive helpers such as
ForFunctionApp<TFunctionApp>(...),ForFunctionAppWithStorage<...>(...),ForFunctionAppWithStorageAndServiceBus<...>(...), orForFunctionAppWithCommonBindings<...>(...). - Live Azure resources or Logic Apps: stay on the
TestFramework.Azurepath; Docker/bootstrap is intentionally a Container concern.
Install
dotnet add package TestFramework.Container.Azure
What It Adds
The package plugs into the run through SetEnv(...) with a DockerAzureEnvironment.
That environment:
- starts the required emulator components before the main timeline steps run
- rewrites registered Azure config entries to the mapped local Docker endpoints
- validates the resolved component graph and binds compatible contracts before startup
- keeps the normal identifier-driven Azure config contract intact
The placeholder config can still be registered explicitly by the test project, but definition classes can also own that registration when a shared test stack wants each component to describe its own shape. Those placeholders act as logical identifiers; the runtime endpoints come from the activated component graph.
The timeline itself still looks like a normal TestFramework timeline. The environment is the switch that makes the run container-backed.
Logic Apps are not supported in the Docker container package. Keep Logic App tests on the live Azure-hosted path instead.
Prerequisites
- Docker Desktop or another compatible Docker engine must be running
- the test project must register the Azure identifiers that the timeline uses
- Service Bus scenarios need a valid topology, preferably through
ConfigureServiceBusTopology(...) - Cosmos scenarios often need emulator-specific client options such as certificate bypass
The packaged file example.local.testsettings.json shows the expected placeholder shape for StorageAccount, CosmosDb, ServiceBus, and SqlDatabase sections. Those values are logical placeholders that DockerAzureEnvironment rewrites to mapped Docker endpoints during the run.
Migrate An Existing Azure Timeline
If you already have a timeline that runs against real Azure, the migration path is intentionally small:
- Keep the timeline itself unchanged.
- Keep the same Azure identifier names in your config stores.
- Register placeholder config values for those identifiers.
- Add emulator-specific client options where required, especially Cosmos certificate bypass.
- Switch the run builder to
SetEnv(DockerAzureEnvironment.For<TRootDefinition>()).
In the normal case, the only runtime change is the SetEnv(...) call plus the definition class that describes the emulator-backed component graph.
Cosmos is the main exception worth calling out explicitly: the emulator uses a development certificate, so tests usually need a CosmosClientOptions override with DangerousAcceptAnyServerCertificateValidator.
Quick Function App Fast Path
When you do not need a reusable multi-component graph yet, start with the helper that matches the bindings your Function App actually uses.
TimelineRun run = await timeline
.SetupRun(serviceProvider)
.SetEnv(DockerAzureEnvironment.ForFunctionAppWithStorageAndServiceBus<MyFunctionApp, MainStorage, MainBus>("Default"))
.RunAsync();
Use the full definition model when you need shared stacks, explicit contracts, or reusable composition across many tests. Use the helper entrypoints when you just need a working local Function App path first.
Golden Sample
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.DependencyInjection;
using TestFramework.Azure;
using TestFramework.Azure.Configuration;
using TestFramework.Azure.Configuration.SpecificConfigs;
using TestFramework.Azure.Extensions;
using TestFramework.Container.Azure;
using TestFramework.Core.Timelines;
using TestFramework.Core.Timelines.Assertions;
using Xunit;
public class ContainerAzureSample
{
private sealed class SampleCosmos : DockerCosmosDefinition<SampleDocument>
{
public override CosmosContainerIdentifier Identifier => "cosmos";
}
private sealed record SampleDocument(string Id, string PartitionKey);
private static readonly Timeline _timeline = Timeline.Create()
.Trigger(AzureExt.Trigger.IsLive.Cosmos("cosmos", AlivenessLevel.Authenticated)).WithTimeOut(TimeSpan.FromMinutes(2))
.Build();
[Fact]
public async Task Timeline_runs_against_container_backed_azure_services()
{
ServiceProvider serviceProvider = new ServiceCollection()
.AddSingleton(ConfigStore<CosmosContainerDbConfig>.Create("cosmos", new CosmosContainerDbConfig
{
ConnectionString = "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;",
DatabaseName = "sample-db",
ContainerName = "sample-container",
}))
.ConfigureCosmosClientOptions(_ => new CosmosClientOptions
{
HttpClientFactory = () => new HttpClient(new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
}),
})
.BuildServiceProvider();
TimelineRun run = await _timeline
.SetupRun(serviceProvider)
.SetEnv(DockerAzureEnvironment.For<SampleCosmos>())
.RunAsync();
run.EnsureRanToCompletion();
run.Should().NotHaveLoggedAnyErrors();
Assert.True(run.EnvironmentContext.Contains(DockerAzureEnvironment.CosmosDbComponentId));
}
}
Why this is the default shape:
- the timeline stays consumer-first and looks like a normal Azure test
SetEnv(DockerAzureEnvironment.For<...>())makes the root component explicit, while dependent components stay with the component type that needs them- assertions focus on the run result and the created environment components
Definition-Based Composition
Use named definition classes when you want the infrastructure shape to be visible in code and easy to share between test projects. Each class should describe one component. When a component needs other components, declare those dependencies through component types. If a shared test stack needs fixed placeholder config, let that component class own the registration for its own identifier instead of scattering detached config objects elsewhere.
The current public model is single-source-of-truth based:
- each definition owns exactly one realized identity
- dependencies are explicit graph edges
- contracts describe compatible reuse between providers and consumers
- Function App definitions own their resource bindings
Include<TDefinition>()makes a definition available, but does not mark it as used on its own
using FunctionApp;
using TestFramework.Container.Azure;
public sealed class MainStorage : DockerStorageDefinition
{
public override StorageAccountIdentifier Identifier => "MainStorage";
}
public sealed class MainDb : DockerCosmosDefinition<SampleDocument>
{
public override CosmosContainerIdentifier Identifier => "MainDb";
}
public sealed class ProcessingReply : DockerServiceBusDefinition
{
public override ServiceBusIdentifier Identifier => "ProcessingReply";
public DockerServiceBusEndpoint Reply
=> DockerServiceBusEndpoint.TopicSubscription("processing-reply", "Default");
protected override void ConfigureServiceBusTopology(DockerServiceBusTopologyBuilder builder)
{
builder.AddNamespace("sbemulatorns", ns => ns
.AddTopic("processing-reply", topic => topic.AddSubscription("Default")));
}
}
public sealed class DefaultFunctionApp : DockerFunctionAppDefinition
{
public override FunctionAppIdentifier Identifier => "Default";
// The payload is mounted into the Functions host, so a project source publishes on the host.
public override ContainerSource Source =>
ContainerSource.Project("../AnalysisProcessor/AnalysisProcessor.csproj").BuiltOnHost();
protected override void Configure(DockerFunctionAppBuilder builder)
{
builder
.UseStorage<MainStorage>()
.UseCosmos<MainDb>()
.UseServiceBusReply<ProcessingReply>(bus => bus.Reply);
}
}
TimelineRun run = await timeline
.SetupRun(serviceProvider)
.SetEnv(DockerAzureEnvironment.For<DefaultFunctionApp>())
.RunAsync();
In that example, including DefaultFunctionApp is enough because its Configure(...) method already declares MainStorage, MainDb, and ProcessingReply by component type.
The component types are the contract: identifier, dependency graph, and, when useful for a shared setup, the default config they own before the environment rewrites runtime endpoints.
.UseStorage<TStorage>() now injects StorageTableName by default when the storage config defines TableContainerName.
Override tableNameSettingName when your Function App uses a different setting name, or pass null to suppress table-name injection entirely.
At runtime, the Function App definition is compiled into a descriptor that carries:
- launch metadata such as image and extra app settings
- dependency edges for graph validation and activation
- resource bindings used to derive the actual app settings inside the Function App container
Shared test stacks often keep that default config on the definition itself. A showroom-style helper can look like this:
private abstract class SharedCosmosDefinition<TDocument> : DockerCosmosDefinition<TDocument>
{
protected sealed override CosmosContainerDbConfig? CreateDefaultConfig() => CreateConfig();
protected abstract CosmosContainerDbConfig CreateConfig();
}
private sealed class MainDb : SharedCosmosDefinition<SampleDocument>
{
public override CosmosContainerIdentifier Identifier => "MainDb";
protected override CosmosContainerDbConfig CreateConfig() => new()
{
ConnectionString = "AccountEndpoint=https://localhost:8081/...",
DatabaseName = "BaseDb",
ContainerName = "Profiles",
};
}
That keeps the identifier, model shape, and default config together in one type instead of splitting them across unrelated helper fields or manual DI registration.
Contracts And Explicit Reuse
Contracts are the preferred mechanism when a consumer should bind to one compatible provider rather than to "whatever happened to be included".
public sealed class ReplyBus : DockerServiceBusDefinition
{
public override ServiceBusIdentifier Identifier => "bus";
protected override void ConfigureContracts(DockerAzureContractBuilder contracts)
{
contracts.Provide(new ServiceBusEndpointContract(
ContractKey: "reply",
ServiceBusIdentifier: Identifier,
EndpointKind: ServiceBusEndpointKind.Queue,
EntityName: "processing-reply"));
}
}
public sealed class ReplyConsumerFunctionApp : DockerFunctionAppDefinition
{
public override FunctionAppIdentifier Identifier => "func";
public override ContainerSource Source =>
ContainerSource.Project("../ReplyConsumer/ReplyConsumer.csproj").BuiltOnHost();
protected override void ConfigureDependencies(DockerAzureDependencyBuilder dependencies)
{
dependencies.Include<ReplyBus>();
}
protected override void ConfigureContracts(DockerAzureContractBuilder contracts)
{
contracts.Require(new ServiceBusEndpointContract(
ContractKey: "reply",
ServiceBusIdentifier: "bus",
EndpointKind: ServiceBusEndpointKind.Queue,
EntityName: "processing-reply"));
}
}
Contract binding happens before runtime startup, so ambiguous or missing providers fail during resolution instead of later during container startup.
Service Bus Topology
The preferred pattern is to describe Service Bus emulator topology fluently on the definition that owns it:
public sealed class ProcessingReply : DockerServiceBusDefinition
{
public override ServiceBusIdentifier Identifier => "ProcessingReply";
protected override void ConfigureServiceBusTopology(DockerServiceBusTopologyBuilder builder)
{
builder.AddNamespace("sbemulatorns", ns => ns
.AddTopic("processing-reply", topic => topic.AddSubscription("Default")));
}
}
Use this when you want the sample to stay self-contained and the topology to live next to the identifier and config it belongs to. If the topology is invalid, the Service Bus component still fails during environment startup before the main timeline steps run.
Function App bindings now select explicit endpoints from the Service Bus definition, for example:
builder.UseServiceBusTrigger<SharedMessaging>(bus => bus.Incoming);
builder.UseServiceBusReply<SharedMessaging>(bus => bus.Reply);
This keeps one definition aligned with one namespace while still binding multiple queue/topic endpoints cleanly.
External JSON files are still supported for compatibility through TopologyConfigPath or ServiceBusTopologyConfigPath, but they are now the fallback option rather than the recommended sample style.
Troubleshooting Notes
- If a definition is included but no container starts for it, verify the timeline requirements or dependent definitions actually activate it.
- If graph validation fails, debug the definition graph first and the timeline second.
- If a Function App host cannot be resolved under referenced build output, the current resolution order prefers the owning project directory and then checks the matching
bin/<Configuration>/net8.0output. Build the owning Function App project before assuming the timeline binding is wrong. - If that fallback path is used, the environment now logs an explicit warning that includes the copied assembly output path and the owning-project output path it selected instead.
- If you are choosing between the local-only, Docker-backed, and live Azure paths, decide once per suite rather than per test, and decide on what the test needs to prove. A test about your own code's logic belongs on the local path, where nothing is started and a run costs milliseconds. A test about how your code behaves against a real storage account, Cosmos container, queue or SQL database belongs here, where the emulators behave like the service without the account. A test about configuration, identity or a service feature no emulator implements belongs on the live path with
TestFramework.Azureagainst a real subscription. Mixing the three mental models inside one suite is what makes container tests feel slow and live tests feel flaky.
Housekeeping
The first Docker work a run does also starts a detached sweep for what a killed test host left behind.
Ryuk reaps containers, networks and volumes and nothing else, so images this framework built, its
published output under tf-* in the temp directory, and the Service Bus topology files it generates
under %TEMP%/TestFramework/servicebus-topologies would otherwise stay forever. Anything of those older
than 24 hours goes.
Note that docker image prune --filter until= measures the image's creation time rather than its last
use, so an image built by a run that has already lasted more than a day is eligible while that run is
still going. Docker refuses to remove an image a running container came from, so the prune skips it.
Set TESTFRAMEWORK_CONTAINER_NO_SWEEP to turn housekeeping off. See the TestFramework.Container
README for the exact set of labels and names it touches.
Queue, Topic, And Subscription Example
Use one fluent topology when a sample or shared stack needs multiple entities at once:
public sealed class SharedMessaging : DockerServiceBusDefinition
{
public override ServiceBusIdentifier Identifier => "messaging";
protected override void ConfigureServiceBusTopology(DockerServiceBusTopologyBuilder builder)
{
builder.AddNamespace("sbemulatorns", ns => ns
.AddQueue("audit-trail")
.AddTopic("orders", topic => topic
.AddSubscription("processor")
.AddSubscription("dead-letter-review"))
.AddTopic("orders-reply", topic => topic
.AddSubscription("default")));
}
}
Practical rule of thumb:
- use
AddQueue(...)for queue-backed send/receive flows - use
AddTopic(..., topic => topic.AddSubscription(...))for pub/sub flows - keep the topology next to the
DockerServiceBusDefinitionorDockerAzureInfrastructureDefinitionthat owns the related identifiers
Typical Pattern
- Register the Azure config stores that your timeline identifiers use, either directly in the test project or through shared component-owned registration helpers.
- Configure emulator-specific client options where needed.
- Build the timeline the same way you would for a normal Azure test.
- Add the root definition through
DockerAzureEnvironment.For<TRootDefinition>()and chain.Include<TDefinition>()only when you need extra available definitions such as infrastructure overrides. - Let artifacts, environment requirements, dependency traversal, and contract bindings decide which concrete resources activate for the run.
- Assert on
TimelineRun, artifacts, andEnvironmentContext.
Scaling Up A Test Suite
The beginner path above is optimized for one readable test. When a suite grows and repeated container startup becomes the bottleneck, switch from per-run environment construction to a hosted environment that boots once and hands out fresh run environments.
The package already exposes that path through DockerAzureHostedCollectionFixture<TState>:
using TestFramework.Azure;
using TestFramework.Azure.Configuration;
using TestFramework.Azure.Configuration.SpecificConfigs;
using TestFramework.Container.Azure;
using TestFramework.Core.Environment;
using Xunit;
[CollectionDefinition(CollectionName, DisableParallelization = true)]
public sealed class DockerAzureHostedCollectionDefinition : ICollectionFixture<DockerAzureHostedFixture>
{
public const string CollectionName = "DockerAzureHosted";
}
public sealed class DockerAzureHostedFixtureState : IDockerAzureHostedFixtureState
{
public IReadOnlyList<EnvironmentRequirement> PersistentRequirements =>
[
new(AzureEnvironmentResourceKinds.Storage, "storage"),
new(AzureEnvironmentResourceKinds.Cosmos, "cosmos"),
new(AzureEnvironmentResourceKinds.FunctionApp, "func"),
];
public DockerAzureEnvironment CreateEnvironment()
=> DockerAzureEnvironment
.For<DefaultFunctionApp>()
.Include<CustomInfrastructure>();
public ConfigInstance CreatePersistentConfig()
=> BuildPersistentConfig();
}
// The base class does not implement IAsyncLifetime; you add it. That keeps xunit out of the package's
// runtime dependencies, and it is what lets a xunit v3 consumer write a ValueTask adapter instead.
public sealed class DockerAzureHostedFixture : DockerAzureHostedCollectionFixture<DockerAzureHostedFixtureState>, IAsyncLifetime;
[Collection(DockerAzureHostedCollectionDefinition.CollectionName)]
public sealed class HostedSuite(DockerAzureHostedFixture fixture)
{
[Fact]
public async Task Uses_a_fresh_run_environment_on_top_of_one_persistent_stack()
{
TimelineRun run = await timeline
.SetupRun()
.SetEnv(fixture.GetEnv())
.RunAsync();
run.EnsureRanToCompletion();
}
}
Note the , IAsyncLifetime on your own fixture. DockerAzureHostedCollectionFixture<TState> does not
implement it: this package is not a test project, and a public base class that implements
Xunit.IAsyncLifetime forces every consumer's runtime to supply that exact type. xunit v3 moved it to
xunit.v3.core with ValueTask returns, so a v3 consumer would meet a TypeLoadException rather than
a build error. InitializeAsync and DisposeAsync are still there with the v2 signatures and satisfy
the interface implicitly, and a v3 consumer can now write the adapter that the hard binding used to make
impossible:
public sealed class DockerAzureHostedFixture : DockerAzureHostedCollectionFixture<DockerAzureHostedFixtureState>, IAsyncLifetime
{
ValueTask IAsyncLifetime.InitializeAsync() => new(InitializeAsync());
ValueTask IAsyncDisposable.DisposeAsync() => new(DisposeAsync());
}
TState describes the complete environment shape and the configuration snapshot used for the hosted stack.
Only the components selected by PersistentRequirements are realized once up front.
Each later GetEnv(...) call still creates a fresh run environment and may add run-local config on top of the persistent snapshot.
Use this path when:
- smoke tests share the same environment shape across many test methods or classes
- container startup dominates test runtime
- you want one project-level helper that centralizes Docker Azure policy instead of rebuilding it in each test
Keep the per-run SetEnv(DockerAzureEnvironment.For<...>()) shape for simple tests and examples.
Move to DockerAzureHostedCollectionFixture<TState> only when suite scale or runtime cost justifies it.
What A Hosted Run Inherits
The containers survive the run, and so does everything written into them. A blob, a table row, a Cosmos item, a storage queue message and a Service Bus message put there by one run are all still there when the next run of the collection starts. The persistent components are not created a second time, so nothing they do at startup happens again either.
The environment therefore purges the resources it declared before each run touches them. That is
AzureResetMode.PurgeDeclaredResources, the default:
| Resource | What the purge does |
|---|---|
| Storage | Deletes every blob container and table on the account, and clears every storage queue. Containers and tables are recreated on demand by the artifact helpers. |
| Cosmos | Deletes the declared container and creates it again with the recorded partition key. Far cheaper than deleting items one by one. |
| Service Bus | Drains the declared queue or topic subscription, dead-letter sub-queue included, with a receive-and-delete receiver. The topology itself is untouched: the emulator reads it from the config file it started with. |
| SQL | Drops and recreates only the databases named by declared SqlDatabaseConfigs. System databases and the Service Bus emulator's own database are never touched — dropping that one ends the emulator mid-suite. |
Only declared resources are in scope, and only a run that was handed already-running containers pays for the purge: a run that started its own emulators skips it, because they came up empty seconds earlier.
One caveat is worth knowing before you rely on the default. Recreating a Cosmos container is cheap against real Cosmos and heavy against the Linux emulator, and on a machine short of memory the emulator has been observed to go away during it — the purge then fails the run with the endpoint it was talking to. If you see that, either give Docker more memory or turn the reset off for that suite.
Turn it off with UseResetMode when a suite deliberately builds state across runs, or when the Cosmos
purge is too heavy for the machine:
public DockerAzureEnvironment CreateEnvironment()
=> DockerAzureEnvironment
.For<DefaultFunctionApp>()
.UseResetMode(AzureResetMode.None);
Keep DisableParallelization = true on the collection definition, as the example above has it. Two runs
of one hosted collection share the same containers, so a parallel run would purge the data another run is
in the middle of asserting on.
Infrastructure Overrides
Use an infrastructure definition when you need explicit emulator-level overrides.
Two of these earn an override on their own. MsSqlImage and AzuriteImage are pinned to a concrete
version by default, but CosmosDbImage and ServiceBusImage are not: the Linux Cosmos emulator ships
only moving tags, and the Service Bus emulator publishes no semantic version tag at all — Microsoft's
own compose templates use latest for it. A pull can therefore change either emulator between runs
with nothing in the repository to show for it. Pin them here, by tag or by digest, when a run has to be
reproducible over time.
MsSqlPassword is the only one you can safely leave alone: without it the environment generates a
password per instance, and ports are published on 127.0.0.1 when the daemon is local, so nothing on
the network can reach the running server. Override it only when something outside the run has to log
in with a password you already know.
public sealed class CustomInfrastructure : DockerAzureInfrastructureDefinition
{
public override string? AzuriteImage => "mcr.microsoft.com/azure-storage/azurite:3.35.0";
public override string? CosmosDbImage => "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview";
public override string? MsSqlImage => "mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04";
public override string? ServiceBusImage => "mcr.microsoft.com/azure-messaging/servicebus-emulator:latest";
public override string? MsSqlPassword => "Your_Own_Password1!";
protected override void ConfigureServiceBusTopology(DockerServiceBusTopologyBuilder builder)
{
builder.AddNamespace("sbemulatorns", ns => ns
.AddQueue("processing-input")
.AddTopic("processing-reply", topic => topic.AddSubscription("Default")));
}
}
TimelineRun run = await timeline
.SetupRun(serviceProvider)
.SetEnv(DockerAzureEnvironment.For<DefaultFunctionApp>().Include<CustomInfrastructure>())
.RunAsync();
Typical cases:
- provide a fluent Service Bus topology override at infrastructure scope
- pin emulator images for a shared test stack
- override SQL credentials for a local test environment
You can still keep using a JSON file when you want an external emulator config, but all new samples should prefer the fluent builder:
public sealed class OrdersBus : DockerServiceBusDefinition
{
public override ServiceBusIdentifier Identifier => "orders-bus";
protected override void ConfigureServiceBusTopology(DockerServiceBusTopologyBuilder builder)
{
builder.AddNamespace("sbemulatorns", ns => ns
.AddTopic("orders", topic => topic.AddSubscription("processor"))
.AddTopic("orders-reply", topic => topic.AddSubscription("default")));
}
}
Smoke Tests
The end-to-end smoke path runs as part of the normal Container Azure test project and no longer relies on an external opt-in flag:
dotnet test .\UnitTests\TestFramework.Container.Azure.Tests\TestFramework.Container.Azure.Tests.csproj -c Release
Related Packages
TestFramework.Azurefor Azure triggers, waits, and artifact typesTestFramework.Configfor building the service provider and config stores used by the runTestFramework.Corefor the base timeline model and run assertions
Further Reading
- Architecture for the single-source-of-truth component model, activation semantics, and Function App runtime binding design
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Azure.Data.Tables (>= 12.9.1)
- Azure.Messaging.ServiceBus (>= 7.20.1)
- Azure.Storage.Blobs (>= 12.26.0)
- Azure.Storage.Queues (>= 12.26.0)
- Microsoft.Azure.Cosmos (>= 3.59.0)
- Microsoft.Data.SqlClient (>= 6.1.2)
- Newtonsoft.Json (>= 13.0.4)
- SSH.NET (>= 2026.0.0)
- Testcontainers (>= 4.11.0)
- Testcontainers.Azurite (>= 4.11.0)
- Testcontainers.CosmosDb (>= 4.11.0)
- Testcontainers.MsSql (>= 4.11.0)
- Testcontainers.ServiceBus (>= 4.11.0)
- TestFramework.Azure (>= 0.4.0)
- TestFramework.Config (>= 0.3.0)
- TestFramework.Container (>= 0.4.0)
- TestFramework.Core (>= 0.4.0)
-
net8.0
- Azure.Data.Tables (>= 12.9.1)
- Azure.Messaging.ServiceBus (>= 7.20.1)
- Azure.Storage.Blobs (>= 12.26.0)
- Azure.Storage.Queues (>= 12.26.0)
- Microsoft.Azure.Cosmos (>= 3.59.0)
- Microsoft.Data.SqlClient (>= 6.1.2)
- Newtonsoft.Json (>= 13.0.4)
- SSH.NET (>= 2026.0.0)
- Testcontainers (>= 4.11.0)
- Testcontainers.Azurite (>= 4.11.0)
- Testcontainers.CosmosDb (>= 4.11.0)
- Testcontainers.MsSql (>= 4.11.0)
- Testcontainers.ServiceBus (>= 4.11.0)
- TestFramework.Azure (>= 0.4.0)
- TestFramework.Config (>= 0.3.0)
- TestFramework.Container (>= 0.4.0)
- TestFramework.Core (>= 0.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|
BREAKING - Function Apps declare where their payload comes from. The entry-point inference is gone with TestFramework.Container 0.3.0: DockerFunctionAppDefinition<TFunctionApp> and DockerFunctionAppRegistration.Create<TFunctionApp> no longer exist, and Source has no default. Override Source with ContainerSource.Project("...").BuiltOnHost() or ContainerSource.Directory(...); the inline ForFunctionApp* helpers take a ContainerSource parameter instead of a function type argument.