Is it possible to use Dependency Injection with xUnit?

前端 未结 4 1216
忘掉有多难
忘掉有多难 2021-02-06 22:25

I have a test class with a constructor that needs an IService.

public class ConsumerTests
{
    private readonly IService          


        
相关标签:
4条回答
  • 2021-02-06 22:55

    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.

    0 讨论(0)
  • 2021-02-06 22:57

    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.

    0 讨论(0)
  • 2021-02-06 23:02

    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

    0 讨论(0)
  • 2021-02-06 23:03

    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

    0 讨论(0)
提交回复
热议问题