Is it possible to use Dependency Injection with xUnit?

陌路散爱 提交于 2019-12-04 23:59:04

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.

Colin Young

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: http://xunit.github.io/docs/shared-context.html.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!