Is it possible to use Dependency Injection with xUnit?
I have a test class with a constructor that needs an IService.
public class ConsumerTests
{
private readonly IService _service;
public ConsumerTests(IService servie)
{
_service = service;
}
[Fact]
public void Should_()
{
//use _service
}
}
I want to plugin my DI container of choice to build the test class.
Is this possible with xUnit?
Yes it's possible with Xunit.DependencyInjection
Install-Package Xunit.DependencyInjection
and you can inject your services
[assembly: TestFramework("Your.Test.Project.Startup", "AssemblyName")]
namespace Your.Test.Project
{
public class Startup : DependencyInjectionTestFramework
{
public Startup(IMessageSink messageSink) : base(messageSink) { }
protected override void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IDependency, DependencyClass>();
}
}
}
https://github.com/pengweiqhca/Xunit.DependencyInjection
Yes there is now, these two questions and answers should be consolidated in my opinion, see answer here
Net Core: Execute All Dependency Injection in Xunit Test for AppService, Repository, etc
Use Custom Web Application Factory and ServiceProvider.GetRequiredService below, feel free to edit and optimize answer
CustomWebApplicationFactory:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((hostingContext, configurationBuilder) =>
{
var type = typeof(TStartup);
var path = @"C:\\OriginalApplication";
configurationBuilder.AddJsonFile($"{path}\\appsettings.json", optional: true, reloadOnChange: true);
configurationBuilder.AddEnvironmentVariables();
});
// if you want to override Physical database with in-memory database
builder.ConfigureServices(services =>
{
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
services.AddDbContext<ApplicationDBContext>(options =>
{
options.UseInMemoryDatabase("DBInMemoryTest");
options.UseInternalServiceProvider(serviceProvider);
});
});
}
}
Integration Test:
public class DepartmentAppServiceTest : IClassFixture<CustomWebApplicationFactory<OriginalApplication.Startup>>
{
public CustomWebApplicationFactory<OriginalApplication.Startup> _factory;
public DepartmentAppServiceTest(CustomWebApplicationFactory<OriginalApplication.Startup> factory)
{
_factory = factory;
_factory.CreateClient();
}
[Fact]
public async Task ValidateDepartmentAppService()
{
using (var scope = _factory.Server.Host.Services.CreateScope())
{
var departmentAppService = scope.ServiceProvider.GetRequiredService<IDepartmentAppService>();
var dbtest = scope.ServiceProvider.GetRequiredService<ApplicationDBContext>();
dbtest.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
dbtest.SaveChanges();
var departmentDto = await departmentAppService.GetDepartmentById(2);
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
}
Resources:
https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2
https://fullstackmark.com/post/20/painless-integration-testing-with-aspnet-core-web-api
There is a way to do this using nuget package out of this source code: https://github.com/dennisroche/xunit.ioc.autofac
It works great as long as you use [Fact]
, but then I got blocked when started using [Theory]
. There is a pull request to sort this out.
To unblock myself, I used CollectionFixture to inject Container and from the container, I resolve the Interface.
What are you trying to test? The implementation of IService
or the wiring of the DI container?
If you are testing IService
implementations, you should be instantiating them directly in the test (and mocking any dependencies):
var service = new MyServiceImplementation(mockDependency1, mockDependency2, ...);
// execute service and do your asserts, probably checking mocks
If you are trying to test the wiring of the DI container, you need to reach out and grab the configured container explicitly. There is no "composition root" that will do that for you (pseudo-code follows, kind of Autofac flavored):
var myContainer = myCompositionRoot.GetContainer();
var service = myContainer.ResolveCompnent<IService>();
// execute service and do your asserts with the actual implementation
If you are using xUnit for running integration tests where you need to use the same object in multiple tests, look at Fixtures: https://xunit.net/docs/shared-context.