diff --git a/Examples.md b/Examples.md new file mode 100644 index 0000000..0cbf2c2 --- /dev/null +++ b/Examples.md @@ -0,0 +1,681 @@ +# Xunit Dependency Injection - Comprehensive Examples + +This document provides comprehensive examples demonstrating all the ways to use the Xunit.Microsoft.DependencyInjection library. All examples are taken from working test code in the `examples/` directory. + +## Table of Contents + +1. [Basic Setup](#basic-setup) +2. [Traditional Fixture-Based Approach](#traditional-fixture-based-approach) +3. [Property Injection (Recommended)](#property-injection-recommended) +4. [Keyed Services](#keyed-services) +5. [Factory Pattern (Experimental)](#factory-pattern-experimental) +6. [Configuration and User Secrets](#configuration-and-user-secrets) +7. [Advanced Dependency Injection Patterns](#advanced-dependency-injection-patterns) +8. [Service Lifetimes](#service-lifetimes) +9. [Test Ordering](#test-ordering) + +## Basic Setup + +### 1. Creating a Test Fixture + +First, create a test fixture that derives from `TestBedFixture`: + +```csharp +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Xunit.Microsoft.DependencyInjection.Abstracts; + +public class TestProjectFixture : TestBedFixture +{ + protected override void AddServices(IServiceCollection services, IConfiguration? configuration) + => services + // Transient services - new instance for each injection + .AddTransient() + .AddTransient() + .AddKeyedTransient("Porsche") + .AddKeyedTransient("Toyota") + + // Scoped services - same instance within a scope (test) + .AddScoped() + + // Singleton services - same instance across entire application lifetime + .AddSingleton() + + // Configure options + .Configure(config => configuration?.GetSection("Options").Bind(config)) + .Configure(config => configuration?.GetSection(nameof(SecretValues)).Bind(config)); + + protected override ValueTask DisposeAsyncCore() + => new(); + + protected override IEnumerable GetTestAppSettings() + { + yield return new() { Filename = "appsettings.json", IsOptional = false }; + } + + protected override void AddUserSecrets(IConfigurationBuilder configurationBuilder) + => configurationBuilder.AddUserSecrets(); +} +``` + +### 2. Configuration File + +Create an `appsettings.json` file in your test project: + +```json +{ + "Options": { + "Rate": 10 + }, + "SecretValues": { + "Secret1": "StoreSecret1InUserSecrets", + "Secret2": "StoreSecret2InUserSecrets" + } +} +``` + +### 3. Example Services + +```csharp +public interface ICalculator +{ + Task AddAsync(int x, int y); +} + +public class Calculator : ICalculator +{ + private readonly Options _option; + private readonly ILogger _logger; + + public Calculator(ILogger logger, IOptions option) + { + _option = option.Value; + _logger = logger; + } + + public Task AddAsync(int x, int y) + { + var result = (x + y) * _option.Rate; + _logger.LogInformation("The result is {@Result}", result); + return Task.FromResult(result); + } +} + +public class Options +{ + public int Rate { get; set; } +} +``` + +## Traditional Fixture-Based Approach + +This is the classic approach that works with all versions of the library: + +```csharp +using Microsoft.Extensions.Options; +using Xunit.Microsoft.DependencyInjection.Abstracts; + +public class CalculatorTests : TestBed +{ + private readonly Options _options; + + public CalculatorTests(ITestOutputHelper testOutputHelper, TestProjectFixture fixture) + : base(testOutputHelper, fixture) + { + _options = _fixture.GetService>(_testOutputHelper)!.Value; + } + + [Theory] + [InlineData(1, 2)] + public async Task TestServiceAsync(int x, int y) + { + // Get service from fixture + var calculator = _fixture.GetService(_testOutputHelper)!; + + // Use the service + var calculatedValue = await calculator.AddAsync(x, y); + var expected = _options.Rate * (x + y); + + Assert.Equal(expected, calculatedValue); + } + + [Theory] + [InlineData(1, 2)] + public async Task TestScopedServiceAsync(int x, int y) + { + // Get scoped service from fixture + var calculator = _fixture.GetScopedService(_testOutputHelper)!; + + var calculatedValue = await calculator.AddAsync(x, y); + var expected = _options.Rate * (x + y); + + Assert.Equal(expected, calculatedValue); + } +} +``` + +### Available Methods in Traditional Approach + +- `_fixture.GetService(_testOutputHelper)` - Gets a service instance +- `_fixture.GetScopedService(_testOutputHelper)` - Gets a scoped service instance +- `_fixture.GetKeyedService("key", _testOutputHelper)` - Gets a keyed service instance +- `_fixture.GetAsyncScope(_testOutputHelper)` - Gets an async service scope + +## Property Injection (Recommended) + +**New in version 9.2.0+**: Clean, declarative syntax using property injection with the `[Inject]` attribute: + +```csharp +using Microsoft.Extensions.Options; +using Xunit.Microsoft.DependencyInjection.Abstracts; +using Xunit.Microsoft.DependencyInjection.Attributes; + +/// +/// Example tests demonstrating property injection using the new TestBedWithDI base class +/// +public class PropertyInjectionTests : TestBedWithDI +{ + // Regular service injection + [Inject] + public ICalculator? Calculator { get; set; } + + [Inject] + public IOptions? Options { get; set; } + + // Keyed service injection + [Inject("Porsche")] + internal ICarMaker? PorscheCarMaker { get; set; } + + [Inject("Toyota")] + internal ICarMaker? ToyotaCarMaker { get; set; } + + public PropertyInjectionTests(ITestOutputHelper testOutputHelper, TestProjectFixture fixture) + : base(testOutputHelper, fixture) + { + // Dependencies are automatically injected after construction + } + + [Fact] + public async Task TestCalculatorThroughPropertyInjection() + { + // Arrange - dependencies are already injected via properties + Assert.NotNull(Calculator); + Assert.NotNull(Options); + + // Act + var result = await Calculator.AddAsync(5, 3); + + // Assert + var expected = Options.Value.Rate * (5 + 3); + Assert.Equal(expected, result); + } + + [Fact] + public void TestKeyedServicesThroughPropertyInjection() + { + // Arrange - keyed services are already injected via properties + Assert.NotNull(PorscheCarMaker); + Assert.NotNull(ToyotaCarMaker); + + // Assert + Assert.Equal("Porsche", PorscheCarMaker.Manufacturer); + Assert.Equal("Toyota", ToyotaCarMaker.Manufacturer); + } + + [Theory] + [InlineData(10, 20)] + public async Task TestConvenienceMethodsStillWork(int x, int y) + { + // Demonstrate that convenience methods from the base class still work + var calculator = GetService(); + var options = GetService>(); + var porsche = GetKeyedService("Porsche"); + + Assert.NotNull(calculator); + Assert.NotNull(options); + Assert.NotNull(porsche); + + var result = await calculator.AddAsync(x, y); + var expected = options.Value.Rate * (x + y); + Assert.Equal(expected, result); + } +} +``` + +### Benefits of Property 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 existing `TestBed` code continues to work unchanged +- ✅ **Gradual migration** - Adopt new approach incrementally without breaking existing tests + +### Available Methods in Property Injection Approach + +- `GetService()` - Gets a service instance (no `_testOutputHelper` parameter needed) +- `GetScopedService()` - Gets a scoped service instance +- `GetKeyedService("key")` - Gets a keyed service instance + +## Keyed Services + +Keyed services are a .NET 9.0 feature that allows you to register multiple implementations of the same interface with different keys: + +### Traditional Approach with Keyed Services + +```csharp +public class KeyedServicesTests : TestBed +{ + public KeyedServicesTests(ITestOutputHelper testOutputHelper, TestProjectFixture fixture) + : base(testOutputHelper, fixture) + { + } + + [Theory] + [InlineData("Porsche")] + [InlineData("Toyota")] + public void GetKeyedService(string key) + { + var carMaker = _fixture.GetKeyedService(key, _testOutputHelper)!; + Assert.Equal(key, carMaker.Manufacturer); + } +} +``` + +### Property Injection with Keyed Services + +```csharp +public class PropertyInjectionTests : TestBedWithDI +{ + [Inject("Porsche")] + internal ICarMaker? PorscheCarMaker { get; set; } + + [Inject("Toyota")] + internal ICarMaker? ToyotaCarMaker { get; set; } + + // ... constructor and other code ... + + [Fact] + public void TestKeyedServices() + { + Assert.NotNull(PorscheCarMaker); + Assert.NotNull(ToyotaCarMaker); + Assert.Equal("Porsche", PorscheCarMaker.Manufacturer); + Assert.Equal("Toyota", ToyotaCarMaker.Manufacturer); + } +} +``` + +### Keyed Service Registration + +```csharp +protected override void AddServices(IServiceCollection services, IConfiguration? configuration) + => services + .AddKeyedTransient("Porsche") + .AddKeyedTransient("Toyota"); + +public interface ICarMaker +{ + string Manufacturer { get; } +} + +public class Porsche : ICarMaker +{ + public string Manufacturer => "Porsche"; +} + +public class Toyota : ICarMaker +{ + public string Manufacturer => "Toyota"; +} +``` + +## Factory Pattern (Experimental) + +For true constructor injection into service classes, you can use the factory pattern: + +### Factory Fixture Setup + +```csharp +public class FactoryTestProjectFixture : TestBedFixture +{ + protected override void AddServices(IServiceCollection services, IConfiguration? configuration) + => services + .AddTransient() + .AddKeyedTransient("Porsche") + .AddKeyedTransient("Toyota") + .Configure(config => configuration?.GetSection("Options").Bind(config)); + + // Same implementation as TestProjectFixture for other methods... +} +``` + +### Factory Tests + +```csharp +/// +/// Example tests demonstrating factory-based constructor injection +/// This approach allows for true constructor injection by creating instances via the fixture factory +/// +public class FactoryConstructorInjectionTests : TestBed +{ + public FactoryConstructorInjectionTests(ITestOutputHelper testOutputHelper, FactoryTestProjectFixture fixture) + : base(testOutputHelper, fixture) + { + } + + [Fact] + public async Task TestSimpleConstructorInjectionViaFactory() + { + // Arrange - Create instance with constructor injection via factory + var simpleService = _fixture.CreateTestInstance(_testOutputHelper); + + // Act + var result = await simpleService.CalculateAsync(10, 5); + var rate = simpleService.GetRate(); + + // Assert + var expected = rate * (10 + 5); + Assert.Equal(expected, result); + } + + [Fact] + public void TestFactoryWithAdditionalParameters() + { + // Create a custom test class that needs both DI services and custom parameters + var testString = "test-data"; + var testInstance = _fixture.CreateTestInstance(_testOutputHelper, testString); + + Assert.NotNull(testInstance.Calculator); + Assert.Equal(testString, testInstance.CustomData); + } +} + +/// +/// Example class that demonstrates constructor injection with both DI services +/// and custom parameters +/// +public class CustomTestClass +{ + public ICalculator Calculator { get; } + public string CustomData { get; } + + public CustomTestClass(ICalculator calculator, string customData) + { + Calculator = calculator ?? throw new ArgumentNullException(nameof(calculator)); + CustomData = customData ?? throw new ArgumentNullException(nameof(customData)); + } +} +``` + +## Configuration and User Secrets + +### Configuration Setup + +The library supports configuration files and user secrets for sensitive data: + +```csharp +protected override IEnumerable GetTestAppSettings() +{ + yield return new() { Filename = "appsettings.json", IsOptional = false }; +} + +protected override void AddUserSecrets(IConfigurationBuilder configurationBuilder) + => configurationBuilder.AddUserSecrets(); +``` + +### Using Configuration in Tests + +```csharp +public class UserSecretTests : TestBed +{ + public UserSecretTests(ITestOutputHelper testOutputHelper, TestProjectFixture fixture) + : base(testOutputHelper, fixture) + { + } + + [Fact] + public void TestSecretValues() + { + /* + * Create a user secret entry like the following payload in user secrets: + * + * "SecretValues": { + * "Secret1": "secret1value", + * "Secret2": "secret2value" + * } + */ + var secretValues = _fixture.GetService>(_testOutputHelper)!.Value; + Assert.NotEmpty(secretValues?.Secret1 ?? string.Empty); + Assert.NotEmpty(secretValues?.Secret2 ?? string.Empty); + } +} + +public record SecretValues +{ + public string? Secret1 { get; set; } + public string? Secret2 { get; set; } +} +``` + +### Setting Up User Secrets + +1. Right-click your test project and select "Manage User Secrets" +2. Add your secret configuration: + +```json +{ + "SecretValues": { + "Secret1": "secret1value", + "Secret2": "secret2value" + } +} +``` + +## Advanced Dependency Injection Patterns + +### IOptions Pattern + +```csharp +public class AdvancedDependencyInjectionTests : TestBedWithDI +{ + [Inject] + public IOptions? Options { get; set; } + + [Fact] + public void TestOptionsPattern() + { + Assert.NotNull(Options); + Assert.True(Options.Value.Rate > 0); + } +} +``` + +### Func Factory Pattern + +Register and use service factories: + +```csharp +// In fixture +protected override void AddServices(IServiceCollection services, IConfiguration? configuration) + => services + .AddTransient() + .AddTransient>(provider => () => provider.GetService()!); + +// In tests +[Inject] +public Func? CalculatorFactory { get; set; } + +[Fact] +public async Task TestFactoryPattern() +{ + Assert.NotNull(CalculatorFactory); + + var calculator = CalculatorFactory(); + var result = await calculator.AddAsync(1, 2); + + Assert.True(result > 0); +} +``` + +### Action Pattern + +```csharp +[Fact] +public void TestActionTPatternWithServices() +{ + var calculatorResults = new List(); + + Action calculatorAction = async calc => + { + var result = await calc.AddAsync(10, 5); + calculatorResults.Add(result); + }; + + // Use the action with injected calculator + calculatorAction(Calculator!); + + Assert.Single(calculatorResults); + Assert.True(calculatorResults[0] > 0); +} +``` + +## Service Lifetimes + +### Transient Services + +New instance for each injection: + +```csharp +public class TransientServiceTests : TestBed +{ + [Fact] + public void TestTransientServicesAreDifferentInstances() + { + var service1 = _fixture.GetService(_testOutputHelper)!; + var service2 = _fixture.GetService(_testOutputHelper)!; + + Assert.NotEqual(service1.InstanceId, service2.InstanceId); + } +} +``` + +### Scoped Services + +Same instance within a scope (test): + +```csharp +public class ScopedServiceTests : TestBed +{ + [Fact] + public void TestScopedServicesAreSameInstanceWithinScope() + { + var service1 = _fixture.GetScopedService(_testOutputHelper)!; + var service2 = _fixture.GetScopedService(_testOutputHelper)!; + + Assert.Equal(service1.InstanceId, service2.InstanceId); + } +} +``` + +### Singleton Services + +Same instance across entire application lifetime: + +```csharp +public class SingletonServiceTests : TestBed +{ + [Fact] + public void TestSingletonServicesAreSameInstance() + { + var service1 = _fixture.GetService(_testOutputHelper)!; + var service2 = _fixture.GetService(_testOutputHelper)!; + + Assert.Equal(service1.InstanceId, service2.InstanceId); + } +} +``` + +## Test Ordering + +The library provides a bonus feature for running tests in order: + +```csharp +[TestCaseOrderer("Xunit.Microsoft.DependencyInjection.TestsOrder.TestPriorityOrderer", "Xunit.Microsoft.DependencyInjection")] +public class UnitTests : TestBed +{ + public UnitTests(ITestOutputHelper testOutputHelper, TestProjectFixture fixture) + : base(testOutputHelper, fixture) + { + } + + [Fact, TestOrder(1)] + public async Task Test1() + { + var calculator = _fixture.GetService(_testOutputHelper)!; + var result = await calculator.AddAsync(1, 2); + Assert.True(result > 0); + } + + [Fact, TestOrder(2)] + public async Task Test2() + { + var calculator = _fixture.GetService(_testOutputHelper)!; + var result = await calculator.AddAsync(3, 4); + Assert.True(result > 0); + } + + [Theory, TestOrder(3)] + [InlineData(5, 6)] + public async Task Test3(int x, int y) + { + var calculator = _fixture.GetService(_testOutputHelper)!; + var result = await calculator.AddAsync(x, y); + Assert.True(result > 0); + } +} +``` + +## Best Practices + +1. **Use Property Injection for new projects** - It provides the cleanest syntax +2. **Gradual Migration** - You can mix both approaches in the same test suite +3. **Keyed Services** - Use for multiple implementations of the same interface +4. **Configuration** - Store non-sensitive data in `appsettings.json`, sensitive data in user secrets +5. **Service Lifetimes** - Choose appropriate lifetimes based on your testing needs +6. **Factory Pattern** - Use for true constructor injection when needed +7. **Test Ordering** - Use sparingly, only when tests have dependencies on each other + +## Migration Guide + +### From Traditional to Property Injection + +**Before:** +```csharp +public class MyTests : TestBed +{ + [Fact] + public async Task TestCalculation() + { + var calculator = _fixture.GetService(_testOutputHelper); + var result = await calculator.AddAsync(1, 2); + Assert.Equal(3, result); + } +} +``` + +**After:** +```csharp +public class MyTests : TestBedWithDI +{ + [Inject] private ICalculator Calculator { get; set; } = null!; + + [Fact] + public async Task TestCalculation() + { + var result = await Calculator.AddAsync(1, 2); + Assert.Equal(3, result); + } +} +``` + +This concludes the comprehensive examples for the Xunit.Microsoft.DependencyInjection library. For more details, visit the [repository examples](https://github.com/Umplify/xunit-dependency-injection/tree/main/examples/Xunit.Microsoft.DependencyInjection.ExampleTests). \ No newline at end of file diff --git a/README.md b/README.md index 09c091c..3d5734a 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,21 @@ 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 brings Microsoft's dependency injection container to Xunit by leveraging Xunit's fixture pattern and now supports **two approaches** for dependency injection: +This 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: -1. **Traditional Fixture-Based Approach** - Access services via `_fixture.GetService(_testOutputHelper)` (fully supported, backward compatible) -2. **Constructor Dependency Injection** - Inject services directly into test class properties using the `[Inject]` attribute (new feature) +1. **🆕 Property Injection (Recommended)** - Clean, declarative syntax using `[Inject]` attributes on properties +2. **🔧 Traditional Fixture-Based** - Access services via `_fixture.GetService(_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 9.0 keyed services integration +- ⚙️ **Configuration integration** - Support for `appsettings.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 by [Digital Silo](https://digitalsilo.io/) and other production applications ## Important: xUnit versions @@ -21,19 +32,125 @@ Also please check the [migration guide](https://xunit.net/docs/getting-started/v ### Example on how to reference xunit.v3 ```xml - + ``` ## Getting started +### Prerequisites + +Before you begin, ensure you have: +- **.NET 9.0 SDK** installed on your development machine +- **Visual Studio 2022** or **Visual Studio Code** with C# extension +- Basic understanding of dependency injection concepts +- Familiarity with xUnit testing framework + ### Nuget package -First add the following [nuget package](https://www.nuget.org/packages/Xunit.Microsoft.DependencyInjection/) to your Xunit project: +First add the following [nuget package](https://www.nuget.org/packages/Xunit.Microsoft.DependencyInjection/) to your Xunit test project: +#### Package Manager Console ```ps Install-Package Xunit.Microsoft.DependencyInjection ``` +#### .NET CLI +```bash +dotnet add package Xunit.Microsoft.DependencyInjection +``` + +#### PackageReference (in your .csproj file) +```xml + +``` + +### Required Dependencies + +Your test project also needs the following Microsoft.Extensions packages for full functionality: + +```xml + + + + + + + + +``` + +### Quick Start Example + +Here's a minimal example to get you started quickly: + +#### 1. Create a Test Fixture + +```csharp +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Xunit.Microsoft.DependencyInjection.Abstracts; + +public class MyTestFixture : TestBedFixture +{ + protected override void AddServices(IServiceCollection services, IConfiguration? configuration) + => services + .AddTransient() + .AddScoped(); + + protected override ValueTask DisposeAsyncCore() => new(); + + protected override IEnumerable GetTestAppSettings() + { + yield return new() { Filename = "appsettings.json", IsOptional = true }; + } +} +``` + +#### 2. Create Your Test Class (Property Injection - Recommended) + +```csharp +using Xunit.Microsoft.DependencyInjection.Abstracts; +using Xunit.Microsoft.DependencyInjection.Attributes; + +[Collection("Dependency Injection")] +public class MyTests : TestBedWithDI +{ + [Inject] private IMyService MyService { get; set; } = null!; + [Inject] private IMyScopedService MyScopedService { get; set; } = null!; + + public MyTests(ITestOutputHelper testOutputHelper, MyTestFixture fixture) + : base(testOutputHelper, fixture) { } + + [Fact] + public async Task TestMyService() + { + // Your services are automatically injected and ready to use + var result = await MyService.DoSomethingAsync(); + Assert.NotNull(result); + } +} +``` + +#### 3. Alternative: Traditional Fixture Approach + +```csharp +[CollectionDefinition("Dependency Injection")] +public class MyTraditionalTests : TestBed +{ + public MyTraditionalTests(ITestOutputHelper testOutputHelper, MyTestFixture fixture) + : base(testOutputHelper, fixture) { } + + [Fact] + public async Task TestMyService() + { + // Get services from the fixture + var myService = _fixture.GetService(_testOutputHelper)!; + var result = await myService.DoSomethingAsync(); + Assert.NotNull(result); + } +} +``` + ### Setup your fixture The 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 two abstract methods: @@ -207,21 +324,75 @@ public IConfigurationBuilder ConfigurationBuilder { get; private set; } ## Examples -* Please [follow this link](https://github.com/Umplify/xunit-dependency-injection/tree/main/examples/Xunit.Microsoft.DependencyInjection.ExampleTests) to view examples utilizing both the traditional fixture-based approach and the new constructor dependency injection features. +📖 **[Complete Examples Documentation](Examples.md)** - Comprehensive guide with working code examples + +* **[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 * **Traditional approach**: See examples using `TestBed` and `_fixture.GetService(_testOutputHelper)` -* **Constructor injection**: See `PropertyInjectionTests.cs` for examples using `TestBedWithDI` with `[Inject]` attributes +* **Property injection**: See `PropertyInjectionTests.cs` for examples using `TestBedWithDI` with `[Inject]` attributes * **Factory pattern**: See `FactoryConstructorInjectionTests.cs` for experimental constructor injection scenarios -* [Digital Silo](https://digitalsilo.io/)'s unit tests and integration tests are using this library. +* **Keyed services**: See `KeyedServicesTests.cs` for .NET 9.0 keyed service examples +* **Configuration**: See `UserSecretTests.cs` for configuration and user secrets integration +* **Advanced patterns**: See `AdvancedDependencyInjectionTests.cs` for `IOptions`, `Func`, and `Action` examples + +🏢 [Digital Silo](https://digitalsilo.io/)'s unit tests and integration tests are using this library in production. ### One more thing -Do not forget to include the following nuget packages to your Xunit project: +Do not forget to include the following nuget packages to your Xunit project. The library requires these Microsoft.Extensions packages for full functionality: + +```xml + + + + + + + + + + + + + + + + + + +``` + +Or install them via Package Manager Console: +```ps +Install-Package Microsoft.Extensions.DependencyInjection +Install-Package Microsoft.Extensions.Configuration +Install-Package Microsoft.Extensions.Options +Install-Package Microsoft.Extensions.Configuration.Binder +Install-Package Microsoft.Extensions.Configuration.FileExtensions +Install-Package Microsoft.Extensions.Configuration.Json +Install-Package Microsoft.Extensions.Logging +Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables +``` + +### Troubleshooting Common Issues + +#### Missing Dependencies +If you encounter build errors, ensure all required Microsoft.Extensions packages are installed with compatible versions. + +#### Configuration File Issues +- Ensure `appsettings.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 +- For **xUnit** packages use Xunit.Microsoft.DependencyInjection versions **up to** 9.0.5 +- For **xUnit.v3** packages use Xunit.Microsoft.DependencyInjection versions **from** 9.1.0 + +### Need Help? -* Microsoft.Extensions.DependencyInjection -* Microsoft.Extensions.Configuration -* Microsoft.Extensions.Options -* Microsoft.Extensions.Configuration.Binder -* Microsoft.Extensions.Configuration.FileExtensions -* Microsoft.Extensions.Configuration.Json -* Microsoft.Extensions.Logging -* Microsoft.Extensions.Configuration.EnvironmentVariables +- 📖 **[Complete Examples Documentation](Examples.md)** - Step-by-step examples for all features +- 🐛 **[GitHub Issues](https://github.com/Umplify/xunit-dependency-injection/issues)** - Report bugs or request features +- 📦 **[NuGet Package](https://www.nuget.org/packages/Xunit.Microsoft.DependencyInjection/)** - Latest releases and changelog +- 📋 **[Migration Guide](https://xunit.net/docs/getting-started/v3/migration)** - For xUnit.v3 migration diff --git a/azure-pipeline-PR.yml b/azure-pipeline-PR.yml index e51b22b..caddc63 100644 --- a/azure-pipeline-PR.yml +++ b/azure-pipeline-PR.yml @@ -17,7 +17,7 @@ steps: displayName: 'Use .NET 9.0 sdk' inputs: packageType: sdk - version: 9.0.304 + version: 9.0.305 installationPath: $(Agent.ToolsDirectory)/dotnet - script: echo Started restoring the source code - task: DotNetCoreCLI@2 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a726ba5..532deeb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ variables: Major: 9 Minor: 2 - Revision: 0 + Revision: 1 BuildConfiguration: Release name: $(Major).$(Minor).$(Revision) @@ -25,7 +25,7 @@ steps: displayName: 'Use .NET 9.0 sdk' inputs: packageType: sdk - version: 9.0.304 + version: 9.0.305 installationPath: $(Agent.ToolsDirectory)/dotnet - script: echo Started restoring the source code - task: DotNetCoreCLI@2 diff --git a/examples/Xunit.Microsoft.DependencyInjection.ExampleTests/Xunit.Microsoft.DependencyInjection.ExampleTests.csproj b/examples/Xunit.Microsoft.DependencyInjection.ExampleTests/Xunit.Microsoft.DependencyInjection.ExampleTests.csproj index 1d1a17a..3124942 100644 --- a/examples/Xunit.Microsoft.DependencyInjection.ExampleTests/Xunit.Microsoft.DependencyInjection.ExampleTests.csproj +++ b/examples/Xunit.Microsoft.DependencyInjection.ExampleTests/Xunit.Microsoft.DependencyInjection.ExampleTests.csproj @@ -11,10 +11,10 @@ - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -22,13 +22,13 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - + + + + + + + diff --git a/src/Xunit.Microsoft.DependencyInjection.csproj b/src/Xunit.Microsoft.DependencyInjection.csproj index 137f01a..eae3aa6 100644 --- a/src/Xunit.Microsoft.DependencyInjection.csproj +++ b/src/Xunit.Microsoft.DependencyInjection.csproj @@ -40,13 +40,13 @@ true - - - - - - - + + + + + + +