{"id":15036234,"url":"https://github.com/umplify/xunit-dependency-injection","last_synced_at":"2026-02-20T03:02:00.928Z","repository":{"id":39920272,"uuid":"313056197","full_name":"Umplify/xunit-dependency-injection","owner":"Umplify","description":":fire: A small library to help .NET developers leverage Microsoft's dependency injection framework in their Xunit-powered test projects","archived":false,"fork":false,"pushed_at":"2025-12-21T15:41:50.000Z","size":475,"stargazers_count":68,"open_issues_count":2,"forks_count":15,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-29T00:27:02.910Z","etag":null,"topics":["c-sharp","csharp","csharp-lib","csharp-library","dependency-injection","dependencyinjection","dotnet","dotnet-core","dotnetcore","microsoft-dependency-injection","test","testing","xunit","xunit-framework","xunit-frameworks","xunit-runner","xunit-test","xunit-tests"],"latest_commit_sha":null,"homepage":"https://umplify.github.io/xunit-dependency-injection/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Umplify.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"Umplify","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2020-11-15T15:02:59.000Z","updated_at":"2025-12-21T15:58:18.000Z","dependencies_parsed_at":"2023-02-12T23:31:36.299Z","dependency_job_id":"ad282197-2977-4142-921d-78f22441b713","html_url":"https://github.com/Umplify/xunit-dependency-injection","commit_stats":{"total_commits":259,"total_committers":5,"mean_commits":51.8,"dds":"0.33204633204633205","last_synced_commit":"d82b6adf51a5efebf7d513daf2be22ec4c075607"},"previous_names":[],"tags_count":81,"template":false,"template_full_name":null,"purl":"pkg:github/Umplify/xunit-dependency-injection","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Umplify%2Fxunit-dependency-injection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Umplify%2Fxunit-dependency-injection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Umplify%2Fxunit-dependency-injection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Umplify%2Fxunit-dependency-injection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Umplify","download_url":"https://codeload.github.com/Umplify/xunit-dependency-injection/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Umplify%2Fxunit-dependency-injection/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29639808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T22:32:43.237Z","status":"online","status_checked_at":"2026-02-20T02:00:07.535Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-sharp","csharp","csharp-lib","csharp-library","dependency-injection","dependencyinjection","dotnet","dotnet-core","dotnetcore","microsoft-dependency-injection","test","testing","xunit","xunit-framework","xunit-frameworks","xunit-runner","xunit-test","xunit-tests"],"created_at":"2024-09-24T20:30:35.704Z","updated_at":"2026-02-20T03:02:00.919Z","avatar_url":"https://github.com/Umplify.png","language":"C#","funding_links":["https://github.com/sponsors/Umplify"],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://dev.azure.com/umplify/Grain/_apis/build/status/Xunit/xunit-dependency-injection-PR?branchName=refs%2Fpull%2F94%2Fmerge)](https://dev.azure.com/umplify/Grain/_build/latest?definitionId=18\u0026branchName=refs%2Fpull%2F94%2Fmerge)\n![Nuget](https://img.shields.io/nuget/v/Xunit.Microsoft.DependencyInjection)\n![Nuget](https://img.shields.io/nuget/dt/Xunit.Microsoft.DependencyInjection)\n\n# Xunit Dependency Injection framework - .NET 10.0\n\nXunit does not support any built-in dependency injection features, therefore developers have to come up with a solution to recruit their favourite dependency injection framework in their tests.\n\nThis library brings **Microsoft's dependency injection container** to Xunit by leveraging Xunit's fixture pattern and provides **three approaches** for dependency injection in your tests:\n\n1. **🆕 Property Injection (Recommended)** - Clean, declarative syntax using `[Inject]` attributes on properties\n2. **🔧 Traditional Fixture-Based** - Access services via `_fixture.GetService\u003cT\u003e(_testOutputHelper)` (fully backward compatible)\n3. **⚡ Factory Pattern** - True constructor injection into service classes (experimental)\n\n## ✨ Key Features\n\n- 🎯 **Multiple injection patterns** - Choose the approach that fits your team's style\n- 🔑 **Keyed services support** - Full .NET 10.0 keyed services integration\n- ⚙️ **Configuration integration** - Support for `appsettings.json`, user secrets, and environment variables\n- 🧪 **Service lifetime management** - Transient, Scoped, and Singleton services work as expected\n- ♻️ **Async disposal support** - Container-managed `IAsyncDisposable` services are disposed asynchronously during fixture teardown\n- 📦 **Microsoft.Extensions ecosystem** - Built on the same DI container used by ASP.NET Core\n- 🔄 **Gradual migration** - Adopt new features incrementally without breaking existing tests\n- 🏗️ **Production-ready** - Used by [Digital Silo](https://digitalsilo.io/) and other production applications\n\n## Important: xUnit versions\n\n* For **xUnit** packages use Xunit.Microsoft.DependencyInjection versions **up to** 9.0.5\n* For **xUnit.v3** packages use Xunit.Microsoft.DependencyInjection versions **from** 9.1.0\n* For **.NET 10.0** use Xunit.Microsoft.DependencyInjection version **10.0.0 or later**\n\nAlso please check the [migration guide](https://xunit.net/docs/getting-started/v3/migration) from xUnit for test authors.\n\n### Example on how to reference xunit.v3\n\n```xml\n\u003cPackageReference Include=\"xunit.v3\" Version=\"3.2.0\" /\u003e\n```\n\n## Getting started\n\n### Prerequisites\n\nBefore you begin, ensure you have:\n- **.NET 10.0 SDK** installed on your development machine\n- **Visual Studio 2022** or **Visual Studio Code** with C# extension\n- Basic understanding of dependency injection concepts\n- Familiarity with xUnit testing framework\n\n### Nuget package\n\nFirst add the following [nuget package](https://www.nuget.org/packages/Xunit.Microsoft.DependencyInjection/) to your Xunit test project:\n\n#### Package Manager Console\n```ps\nInstall-Package Xunit.Microsoft.DependencyInjection\n```\n\n#### .NET CLI\n```bash\ndotnet add package Xunit.Microsoft.DependencyInjection\n```\n\n#### PackageReference (in your .csproj file)\n```xml\n\u003cPackageReference Include=\"Xunit.Microsoft.DependencyInjection\" Version=\"9.2.0\" /\u003e\n```\n\n**✨ That's it!** All required Microsoft.Extensions dependencies are now automatically included with the package, so you don't need to manually add them to your test project.\n\n### Quick Start Example\n\nHere's a minimal example to get you started quickly:\n\n#### 1. Create a Test Fixture\n\n```csharp\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit.Microsoft.DependencyInjection.Abstracts;\n\npublic class MyTestFixture : TestBedFixture\n{\n    protected override void AddServices(IServiceCollection services, IConfiguration? configuration)\n        =\u003e services\n            .AddTransient\u003cIMyService, MyService\u003e()\n            .AddScoped\u003cIMyScopedService, MyScopedService\u003e();\n\n    protected override ValueTask DisposeAsyncCore() =\u003e new();\n\n    protected override IEnumerable\u003cTestAppSettings\u003e GetTestAppSettings()\n    {\n        yield return new() { Filename = \"appsettings.json\", IsOptional = true };\n    }\n}\n```\n\n#### 2. Create Your Test Class (Property Injection - Recommended)\n\n```csharp\nusing Xunit.Microsoft.DependencyInjection.Abstracts;\nusing Xunit.Microsoft.DependencyInjection.Attributes;\n\n[Collection(\"Dependency Injection\")]\npublic class MyTests : TestBedWithDI\u003cMyTestFixture\u003e\n{\n    [Inject] private IMyService MyService { get; set; } = null!;\n    [Inject] private IMyScopedService MyScopedService { get; set; } = null!;\n\n    public MyTests(ITestOutputHelper testOutputHelper, MyTestFixture fixture)\n        : base(testOutputHelper, fixture) { }\n\n    [Fact]\n    public async Task TestMyService()\n    {\n        // Your services are automatically injected and ready to use\n        var result = await MyService.DoSomethingAsync();\n        Assert.NotNull(result);\n    }\n}\n```\n\n#### 3. Alternative: Traditional Fixture Approach\n\n```csharp\n[CollectionDefinition(\"Dependency Injection\")]\npublic class MyTraditionalTests : TestBed\u003cMyTestFixture\u003e\n{\n    public MyTraditionalTests(ITestOutputHelper testOutputHelper, MyTestFixture fixture)\n        : base(testOutputHelper, fixture) { }\n\n    [Fact]\n    public async Task TestMyService()\n    {\n        // Get services from the fixture\n        var myService = _fixture.GetService\u003cIMyService\u003e(_testOutputHelper)!;\n        var result = await myService.DoSomethingAsync();\n        Assert.NotNull(result);\n    }\n}\n```\n\n### Setup your fixture\n\nThe abstract class of `Xunit.Microsoft.DependencyInjection.Abstracts.TestBedFixture` contains the necessary functionalities to add services and configurations to Microsoft's dependency injection container. Your concrete test fixture class must derive from this abstract class and implement the following abstract methods:\n\n```csharp\nprotected abstract void AddServices(IServiceCollection services, IConfiguration? configuration);\nprotected abstract IEnumerable\u003cTestAppSettings\u003e GetTestAppSettings();\nprotected abstract ValueTask DisposeAsyncCore();\n```\n\nUse `DisposeAsyncCore()` to clean up fixture-owned resources (for example, files, sockets, or external clients created by the fixture). Service cleanup for dependencies resolved from the DI container is handled by the framework during async teardown.\n\n`TestBedFixture` now ignores any `TestAppSettings` entries whose `Filename` is null or empty before calling `AddJsonFile`. That means you can safely return placeholder descriptors or rely only on environment variables; optional JSON files can simply leave `Filename` blank and the framework skips them automatically when building the configuration root.\n \n`GetConfigurationFiles(...)` method returns a collection of the configuration files in your Xunit test project to the framework. `AddServices(...)` method must be used to wire up the implemented services.\n\n#### Secret manager\n\n[Secret manager](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-8.0\u0026tabs=windows#how-the-secret-manager-tool-works) is a great tool to store credentials, API keys, and other secret information for development purposes. This library has started supporting user secrets from version 8.2.0 onwards. To utilize user secrets in your tests, simply override the `virtual` method below from the `TestBedFixture` class:\n\n```csharp\nprotected override void AddUserSecrets(IConfigurationBuilder configurationBuilder); \n```\n\n### Access the wired up services\n\nThere are two method that you can use to access the wired up service depending on your context:\n\n```csharp\npublic T GetScopedService\u003cT\u003e(ITestOutputHelper testOutputHelper);\npublic T GetService\u003cT\u003e(ITestOutputHelper testOutputHelper);\n```\n\nTo access async scopes simply call the following method in the abstract fixture class:\n\n```csharp\npublic AsyncServiceScope GetAsyncScope(ITestOutputHelper testOutputHelper);\n```\n\n### Accessing the keyed wired up services in .NET 9.0\n\nYou can call the following method to access the keyed already-wired up services:\n\n```csharp\nT? GetKeyedService\u003cT\u003e([DisallowNull] string key, ITestOutputHelper testOutputHelper);\n```\n\n## Constructor Dependency Injection\n\n**New in this version (ver 9.2.0 and beyond)**: The library now supports constructor-style dependency injection while maintaining full backward compatibility with the existing fixture-based approach.\n\n### Property Injection with TestBedWithDI (Recommended)\n\nFor cleaner test code, inherit from `TestBedWithDI\u003cTFixture\u003e` instead of `TestBed\u003cTFixture\u003e` and use the `[Inject]` attribute:\n\n```csharp\npublic class PropertyInjectionTests : TestBedWithDI\u003cTestProjectFixture\u003e\n{\n    [Inject]\n    public ICalculator? Calculator { get; set; }\n\n    [Inject]\n    public IOptions\u003cOptions\u003e? Options { get; set; }\n\n    public PropertyInjectionTests(ITestOutputHelper testOutputHelper, TestProjectFixture fixture)\n        : base(testOutputHelper, fixture)\n    {\n        // Dependencies are automatically injected after construction\n    }\n\n    [Fact]\n    public async Task TestWithCleanSyntax()\n    {\n        // Dependencies are immediately available - no fixture calls needed\n        Assert.NotNull(Calculator);\n        var result = await Calculator.AddAsync(5, 3);\n        Assert.True(result \u003e 0);\n    }\n}\n```\n\n### Keyed Services with Property Injection\n\nUse the `[Inject(\"key\")]` attribute for keyed services:\n\n```csharp\npublic class PropertyInjectionTests : TestBedWithDI\u003cTestProjectFixture\u003e\n{\n    [Inject(\"Porsche\")]\n    internal ICarMaker? PorscheCarMaker { get; set; }\n\n    [Inject(\"Toyota\")]\n    internal ICarMaker? ToyotaCarMaker { get; set; }\n\n    [Fact]\n    public void TestKeyedServices()\n    {\n        Assert.NotNull(PorscheCarMaker);\n        Assert.NotNull(ToyotaCarMaker);\n        Assert.Equal(\"Porsche\", PorscheCarMaker.Manufacturer);\n        Assert.Equal(\"Toyota\", ToyotaCarMaker.Manufacturer);\n    }\n}\n```\n\n### Convenience Methods\n\nThe `TestBedWithDI` class provides convenience methods that don't require the `_testOutputHelper` parameter:\n\n```csharp\nprotected T? GetService\u003cT\u003e()\nprotected T? GetScopedService\u003cT\u003e()\nprotected T? GetKeyedService\u003cT\u003e(string key)\n```\n\n### Benefits of Constructor Dependency Injection\n\n- ✅ **Clean, declarative syntax** - Use `[Inject]` attribute on properties\n- ✅ **No manual fixture calls** - Dependencies available immediately in test methods  \n- ✅ **Full keyed services support** - Both regular and keyed services work seamlessly\n- ✅ **Backward compatible** - All existing `TestBed\u003cTFixture\u003e` code continues to work unchanged\n- ✅ **Gradual migration** - Adopt new approach incrementally without breaking existing tests\n\n### Migration Guide\n\nYou can migrate existing tests gradually:\n\n1. **Keep existing approach** - Continue using `TestBed\u003cTFixture\u003e` with fixture methods\n2. **Hybrid approach** - Change to `TestBedWithDI\u003cTFixture\u003e` and use both `[Inject]` properties and fixture methods\n3. **Full migration** - Use property injection for all dependencies for cleanest code\n\n### Factory Pattern (Experimental)\n\nFor true constructor injection into service classes, see [CONSTRUCTOR_INJECTION.md](CONSTRUCTOR_INJECTION.md) for the factory-based approach.\n\n### Adding custom logging provider\n\nTest developers can add their own desired logger provider by overriding ```AddLoggingProvider(...)``` virtual method defined in ```TestBedFixture``` class.\n\n### Preparing Xunit test classes\n\nYour Xunit test class must be derived from ```Xunit.Microsoft.DependencyInjection.Abstracts.TestBed\u003cT\u003e``` class where ```T``` should be your fixture class derived from ```TestBedFixture```.\n\nAlso, the test class should be decorated by the following attribute:\n\n```csharp\n[CollectionDefinition(\"Dependency Injection\")]\n```\n\n#### Clearing managed resources\n\nTo have managed resources cleaned up, simply override the virtual method of `Clear()`. This is an optional step.\n\n#### Clearing managed resources asynchronously\n\n`TestBedFixture` performs async teardown and disposes the DI `ServiceProvider` asynchronously. This ensures container-managed services implementing `IAsyncDisposable` are disposed correctly during fixture teardown.\n\nIf you need additional async cleanup for fixture-owned resources, override `DisposeAsyncCore()`:\n\n```csharp\npublic sealed class MyTestFixture : TestBedFixture\n{\n    protected override ValueTask DisposeAsyncCore()\n    {\n        // Cleanup resources created/owned by the fixture itself.\n        return ValueTask.CompletedTask;\n    }\n}\n```\n\nFor a full working example, see `AsyncDisposableTests` and `AsyncDisposableFixture` in the examples project.\n\n## Running tests in order\n\nThe library also has a bonus feature that simplifies running tests in order. The test class does not have to be derived from ```TestBed\u003cT\u003e``` class though and it can apply to all Xunit classes.\n\nDecorate your Xunit test class with the following attribute and associate ```TestOrder(...)``` with ```Fact``` and ```Theory```:\n\n```csharp\n[TestCaseOrderer(\"Xunit.Microsoft.DependencyInjection.TestsOrder.TestPriorityOrderer\", \"Xunit.Microsoft.DependencyInjection\")]\n```\n\n## Supporting configuration from `UserSecrets`\n\nThis library's `TestBedFixture` abstract class exposes an instance of `IConfigurationBuilder` that can be used to support `UserSecrets` when configuring the test projects:\n\n```csharp\npublic IConfigurationBuilder ConfigurationBuilder { get; private set; }\n```\n\n## Examples\n\n📖 **[Complete Examples Documentation](Examples.md)** - Comprehensive guide with working code examples\n\n* **[Live Examples](https://github.com/Umplify/xunit-dependency-injection/tree/main/examples/Xunit.Microsoft.DependencyInjection.ExampleTests)** - View the complete working examples that demonstrate all features\n* **Traditional approach**: See examples using `TestBed\u003cTFixture\u003e` and `_fixture.GetService\u003cT\u003e(_testOutputHelper)`  \n* **Property injection**: See `PropertyInjectionTests.cs` for examples using `TestBedWithDI\u003cTFixture\u003e` with `[Inject]` attributes\n* **Factory pattern**: See `FactoryConstructorInjectionTests.cs` for experimental constructor injection scenarios\n* **Keyed services**: See `KeyedServicesTests.cs` for .NET 9.0 keyed service examples\n* **Configuration**: See `UserSecretTests.cs` for configuration and user secrets integration\n* **Async disposal**: See `AsyncDisposableTests.cs` and `Fixtures/AsyncDisposableFixture.cs` for async teardown of `IAsyncDisposable` services\n* **Advanced patterns**: See `AdvancedDependencyInjectionTests.cs` for `IOptions\u003cT\u003e`, `Func\u003cT\u003e`, and `Action\u003cT\u003e` examples\n\n🏢 [Digital Silo](https://digitalsilo.io/)'s unit tests and integration tests are using this library in production.\n\n### Troubleshooting Common Issues\n\n#### Missing Dependencies\nIf you encounter build errors, ensure all required Microsoft.Extensions packages are installed with compatible versions.\n\n#### Configuration File Issues\n- Ensure `appsettings.json` is set to \"Copy to Output Directory: Copy if newer\" in file properties\n- Configuration files must be valid JSON format\n\n#### User Secrets Issues\n- Initialize user secrets: `dotnet user-secrets init`\n- Set secrets: `dotnet user-secrets set \"SecretKey\" \"SecretValue\"`\n\n#### xUnit Version Compatibility\n- For **xUnit** packages use Xunit.Microsoft.DependencyInjection versions **up to** 9.0.5\n- For **xUnit.v3** packages use Xunit.Microsoft.DependencyInjection versions **from** 9.1.0\n\n### Need Help?\n\n- 📖 **[Complete Examples Documentation](Examples.md)** - Step-by-step examples for all features\n- 🐛 **[GitHub Issues](https://github.com/Umplify/xunit-dependency-injection/issues)** - Report bugs or request features\n- 📦 **[NuGet Package](https://www.nuget.org/packages/Xunit.Microsoft.DependencyInjection/)** - Latest releases and changelog\n- 📋 **[Migration Guide](https://xunit.net/docs/getting-started/v3/migration)** - For xUnit.v3 migration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumplify%2Fxunit-dependency-injection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fumplify%2Fxunit-dependency-injection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumplify%2Fxunit-dependency-injection/lists"}