Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

🔥 A small library to help .NET developers leverage Microsoft's dependency injection framework in their Xunit-powered test projects

License

NotificationsYou must be signed in to change notification settings

Umplify/xunit-dependency-injection

Repository files navigation

Build StatusNugetNuget

Xunit Dependency Injection framework - .NET 10.0

Xunit 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.

This library bringsMicrosoft's dependency injection container to Xunit by leveraging Xunit's fixture pattern and providesthree approaches for dependency injection in your tests:

  1. 🆕 Property Injection (Recommended) - Clean, declarative syntax using[Inject] attributes on properties
  2. 🔧 Traditional Fixture-Based - Access services via_fixture.GetService<T>(_testOutputHelper) (fully backward compatible)
  3. ⚡ Factory Pattern - True constructor injection into service classes (experimental)

✨ Key Features

  • 🎯Multiple injection patterns - Choose the approach that fits your team's style
  • 🔑Keyed services support - Full .NET 10.0 keyed services integration
  • ⚙️Configuration integration - Support forappsettings.json, user secrets, and environment variables
  • 🧪Service lifetime management - Transient, Scoped, and Singleton services work as expected
  • 📦Microsoft.Extensions ecosystem - Built on the same DI container used by ASP.NET Core
  • 🔄Gradual migration - Adopt new features incrementally without breaking existing tests
  • 🏗️Production-ready - Used byDigital Silo and other production applications

Important: xUnit versions

  • ForxUnit packages use Xunit.Microsoft.DependencyInjection versionsup to 9.0.5
  • ForxUnit.v3 packages use Xunit.Microsoft.DependencyInjection versionsfrom 9.1.0
  • For.NET 10.0 use Xunit.Microsoft.DependencyInjection version10.0.0 or later

Also please check themigration guide from xUnit for test authors.

Example on how to reference xunit.v3

<PackageReferenceInclude="xunit.v3"Version="3.2.0" />

Getting started

Prerequisites

Before you begin, ensure you have:

  • .NET 10.0 SDK installed on your development machine
  • Visual Studio 2022 orVisual Studio Code with C# extension
  • Basic understanding of dependency injection concepts
  • Familiarity with xUnit testing framework

Nuget package

First add the followingnuget package to your Xunit test project:

Package Manager Console

Install-PackageXunit.Microsoft.DependencyInjection

.NET CLI

dotnet add package Xunit.Microsoft.DependencyInjection

PackageReference (in your .csproj file)

<PackageReferenceInclude="Xunit.Microsoft.DependencyInjection"Version="9.2.0" />

✨ 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.

Quick Start Example

Here's a minimal example to get you started quickly:

1. Create a Test Fixture

usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;usingXunit.Microsoft.DependencyInjection.Abstracts;publicclassMyTestFixture:TestBedFixture{protectedoverridevoidAddServices(IServiceCollectionservices,IConfiguration?configuration)=>services.AddTransient<IMyService,MyService>().AddScoped<IMyScopedService,MyScopedService>();protectedoverrideValueTaskDisposeAsyncCore()=>new();protectedoverrideIEnumerable<TestAppSettings>GetTestAppSettings(){yieldreturnnew(){Filename="appsettings.json",IsOptional=true};}}

2. Create Your Test Class (Property Injection - Recommended)

usingXunit.Microsoft.DependencyInjection.Abstracts;usingXunit.Microsoft.DependencyInjection.Attributes;[Collection("Dependency Injection")]publicclassMyTests:TestBedWithDI<MyTestFixture>{[Inject]privateIMyServiceMyService{get;set;}=null!;[Inject]privateIMyScopedServiceMyScopedService{get;set;}=null!;publicMyTests(ITestOutputHelpertestOutputHelper,MyTestFixturefixture):base(testOutputHelper,fixture){}[Fact]publicasyncTaskTestMyService(){// Your services are automatically injected and ready to usevarresult=awaitMyService.DoSomethingAsync();Assert.NotNull(result);}}

3. Alternative: Traditional Fixture Approach

[CollectionDefinition("Dependency Injection")]publicclassMyTraditionalTests:TestBed<MyTestFixture>{publicMyTraditionalTests(ITestOutputHelpertestOutputHelper,MyTestFixturefixture):base(testOutputHelper,fixture){}[Fact]publicasyncTaskTestMyService(){// Get services from the fixturevarmyService=_fixture.GetService<IMyService>(_testOutputHelper)!;varresult=awaitmyService.DoSomethingAsync();Assert.NotNull(result);}}

Setup your fixture

The abstract class ofXunit.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 two abstract methods:

protectedabstractvoidAddServices(IServiceCollectionservices,IConfiguration?configuration);protectedabstractIEnumerable<TestAppSettings>GetTestAppSettings();protectedabstractValueTaskDisposeAsyncCore();

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.

Secret manager

Secret manager 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 thevirtual method below from theTestBedFixture class:

protectedoverridevoidAddUserSecrets(IConfigurationBuilderconfigurationBuilder);

Access the wired up services

There are two method that you can use to access the wired up service depending on your context:

publicTGetScopedService<T>(ITestOutputHelpertestOutputHelper);publicTGetService<T>(ITestOutputHelpertestOutputHelper);

To access async scopes simply call the following method in the abstract fixture class:

publicAsyncServiceScopeGetAsyncScope(ITestOutputHelpertestOutputHelper);

Accessing the keyed wired up services in .NET 9.0

You can call the following method to access the keyed already-wired up services:

T?GetKeyedService<T>([DisallowNull]stringkey,ITestOutputHelpertestOutputHelper);

Constructor Dependency Injection

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.

Property Injection with TestBedWithDI (Recommended)

For cleaner test code, inherit fromTestBedWithDI<TFixture> instead ofTestBed<TFixture> and use the[Inject] attribute:

publicclassPropertyInjectionTests:TestBedWithDI<TestProjectFixture>{[Inject]publicICalculator?Calculator{get;set;}[Inject]publicIOptions<Options>?Options{get;set;}publicPropertyInjectionTests(ITestOutputHelpertestOutputHelper,TestProjectFixturefixture):base(testOutputHelper,fixture){// Dependencies are automatically injected after construction}[Fact]publicasyncTaskTestWithCleanSyntax(){// Dependencies are immediately available - no fixture calls neededAssert.NotNull(Calculator);varresult=awaitCalculator.AddAsync(5,3);Assert.True(result>0);}}

Keyed Services with Property Injection

Use the[Inject("key")] attribute for keyed services:

publicclassPropertyInjectionTests:TestBedWithDI<TestProjectFixture>{[Inject("Porsche")]internalICarMaker?PorscheCarMaker{get;set;}[Inject("Toyota")]internalICarMaker?ToyotaCarMaker{get;set;}[Fact]publicvoidTestKeyedServices(){Assert.NotNull(PorscheCarMaker);Assert.NotNull(ToyotaCarMaker);Assert.Equal("Porsche",PorscheCarMaker.Manufacturer);Assert.Equal("Toyota",ToyotaCarMaker.Manufacturer);}}

Convenience Methods

TheTestBedWithDI class provides convenience methods that don't require the_testOutputHelper parameter:

protectedT?GetService<T>()protectedT?GetScopedService<T>()protectedT?GetKeyedService<T>(stringkey)

Benefits of Constructor Dependency Injection

  • Clean, declarative syntax - Use[Inject] attribute on properties
  • No manual fixture calls - Dependencies available immediately in test methods
  • Full keyed services support - Both regular and keyed services work seamlessly
  • Backward compatible - All existingTestBed<TFixture> code continues to work unchanged
  • Gradual migration - Adopt new approach incrementally without breaking existing tests

Migration Guide

You can migrate existing tests gradually:

  1. Keep existing approach - Continue usingTestBed<TFixture> with fixture methods
  2. Hybrid approach - Change toTestBedWithDI<TFixture> and use both[Inject] properties and fixture methods
  3. Full migration - Use property injection for all dependencies for cleanest code

Factory Pattern (Experimental)

For true constructor injection into service classes, seeCONSTRUCTOR_INJECTION.md for the factory-based approach.

Adding custom logging provider

Test developers can add their own desired logger provider by overridingAddLoggingProvider(...) virtual method defined inTestBedFixture class.

Preparing Xunit test classes

Your Xunit test class must be derived fromXunit.Microsoft.DependencyInjection.Abstracts.TestBed<T> class whereT should be your fixture class derived fromTestBedFixture.

Also, the test class should be decorated by the following attribute:

[CollectionDefinition("Dependency Injection")]

Clearing managed resources

To have managed resources cleaned up, simply override the virtual method ofClear(). This is an optional step.

Clearing managed resourced asynchronously

Simply override the virtual method ofDisposeAsyncCore() for this purpose. This is also an optional step.

Running tests in order

The library also has a bonus feature that simplifies running tests in order. The test class does not have to be derived fromTestBed<T> class though and it can apply to all Xunit classes.

Decorate your Xunit test class with the following attribute and associateTestOrder(...) withFact andTheory:

[TestCaseOrderer("Xunit.Microsoft.DependencyInjection.TestsOrder.TestPriorityOrderer","Xunit.Microsoft.DependencyInjection")]

Supporting configuration fromUserSecrets

This library'sTestBedFixture abstract class exposes an instance ofIConfigurationBuilder that can be used to supportUserSecrets when configuring the test projects:

publicIConfigurationBuilderConfigurationBuilder{get;privateset;}

Examples

📖Complete Examples Documentation - Comprehensive guide with working code examples

  • Live Examples - View the complete working examples that demonstrate all features
  • Traditional approach: See examples usingTestBed<TFixture> and_fixture.GetService<T>(_testOutputHelper)
  • Property injection: SeePropertyInjectionTests.cs for examples usingTestBedWithDI<TFixture> with[Inject] attributes
  • Factory pattern: SeeFactoryConstructorInjectionTests.cs for experimental constructor injection scenarios
  • Keyed services: SeeKeyedServicesTests.cs for .NET 9.0 keyed service examples
  • Configuration: SeeUserSecretTests.cs for configuration and user secrets integration
  • Advanced patterns: SeeAdvancedDependencyInjectionTests.cs forIOptions<T>,Func<T>, andAction<T> examples

🏢Digital Silo's unit tests and integration tests are using this library in production.

Troubleshooting Common Issues

Missing Dependencies

If you encounter build errors, ensure all required Microsoft.Extensions packages are installed with compatible versions.

Configuration File Issues

  • Ensureappsettings.json is set to "Copy to Output Directory: Copy if newer" in file properties
  • Configuration files must be valid JSON format

User Secrets Issues

  • Initialize user secrets:dotnet user-secrets init
  • Set secrets:dotnet user-secrets set "SecretKey" "SecretValue"

xUnit Version Compatibility

  • ForxUnit packages use Xunit.Microsoft.DependencyInjection versionsup to 9.0.5
  • ForxUnit.v3 packages use Xunit.Microsoft.DependencyInjection versionsfrom 9.1.0

Need Help?

Packages

No packages published

Contributors5


[8]ページ先頭

©2009-2025 Movatter.jp