Net Core:在 Xunit 测试中为 AppService、Repository 等执行所有依赖注入 [英] Net Core: Execute All Dependency Injection in Xunit Test for AppService, Repository, etc

查看:25
本文介绍了Net Core:在 Xunit 测试中为 AppService、Repository 等执行所有依赖注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 AppService 的 Xunit 测试中实现依赖注入.理想的目标是运行原始应用程序启动/配置,并使用启动中的任何依赖注入,而不是在我的测试中再次重新初始化所有 DI,这就是有问题的整个目标.

I am trying to implement Dependency Injection in Xunit test for AppService. Ideal goal is to run the original application program Startup/configuration, and use any dependency injection that was in Startup, instead of reinitializing all the DI again in my test, thats the whole Goal in question.

更新:Mohsen 的回答很接近.需要更新几个语法/要求错误才能工作.

Update: Mohsen's answer is close. Need to update couple syntax/requirement errors to work.

由于某种原因,原始应用程序可以运行并且可以调用部门应用服务.但是,它不能在 Xunit 中调用.最终使用来自原始应用程序的启动和配置使 Testserver 工作.现在收到以下错误:

For some reason, original application works and can call Department App Service. However, it cannot call in Xunit. Finally got Testserver working using Startup and Configuration from original application. Now receiving error below:

Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService

namespace Testing.IntegrationTests
{
    public class DepartmentAppServiceTest
    {
        public DBContext context;
        public IDepartmentAppService departmentAppService;

        public DepartmentAppServiceTest(IDepartmentAppService departmentAppService)
        {
            this.departmentAppService = departmentAppService;
        }

        [Fact]
        public async Task Get_DepartmentById_Are_Equal()
        {
            var options = new DbContextOptionsBuilder<SharedServicesContext>()
                .UseInMemoryDatabase(databaseName: "TestDatabase")
                .Options;
            context = new DBContext(options);

            TestServer _server = new TestServer(new WebHostBuilder()
                .UseContentRoot("C:\OriginalApplication")
                .UseEnvironment("Development")
                .UseConfiguration(new ConfigurationBuilder()
                    .SetBasePath("C:\OriginalApplication")
                    .AddJsonFile("appsettings.json")
                    .Build()).UseStartup<Startup>());

            context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
            context.SaveChanges();

            var departmentDto = await departmentAppService.GetDepartmentById(2);

            Assert.Equal("123", departmentDto.DepartmentCode);
        }
    }
}

我收到此错误:

Message: The following constructor parameters did not have matching fixture data: IDepartmentAppService departmentAppService

在测试中需要像真正的应用程序一样使用依赖注入.原始应用程序执行此操作.下面的答案目前还不够,一个使用不是当前目标的模拟,其他答案使用绕过问题目的的控制器.

Need to use Dependency injection in testing just like real application. Original application does this. Answers below are not currently sufficient , one uses mocking which is not current goal, other answer uses Controller which bypass question purpose.

注意:IDepartmentAppService 依赖于 IDepartmentRepository,IDepartmentRepository 也注入到 Startup 类中,以及 Automapper 依赖项.这就是调用整个启动类的原因.

Note: IDepartmentAppService has dependency on IDepartmentRepository which is also injected in Startup class, and Automapper dependencies. This is why calling the whole startup class.

好的资源:

如何对asp进行单元测试具有构造函数依赖注入的 .net 核心应用程序

Xunit 项目中的依赖注入

推荐答案

您正在混合单元测试和集成测试.TestServer 用于集成测试,如果您想重用 Startup 类以避免再次注册依赖项,您应该使用 HttpClient 并对控制器进行 HTTP 调用和使用 IDepartmentAppService 的操作.

You are mixing unit test with integration test. TestServer is for integration test and if you want to reuse Startup class to avoid register dependencies again, you should use HttpClient and make HTTP call to controller and action that use IDepartmentAppService.

如果你想做单元测试,你需要设置DI并注册所有需要的依赖来测试IDepartmentAppService.

If you want do unit test, you need to setup DI and register all needed dependencies to test IDepartmentAppService.

通过测试夹具使用 DI:

public class DependencySetupFixture
{
    public DependencySetupFixture()
    {
         var serviceCollection = new ServiceCollection();
         serviceCollection.AddDbContext<SharedServicesContext>(options => options.UseInMemoryDatabase(databaseName: "TestDatabase"));
         serviceCollection.AddTransient<IDepartmentRepository, DepartmentRepository>();
         serviceCollection.AddTransient<IDepartmentAppService, DepartmentAppService>();

         ServiceProvider = serviceCollection.BuildServiceProvider();
    }

    public ServiceProvider ServiceProvider { get; private set; }
}

public class DepartmentAppServiceTest : IClassFixture<DependencySetupFixture>
{
    private ServiceProvider _serviceProvide;

    public DepartmentAppServiceTest(DependencySetupFixture fixture)
    {
        _serviceProvide = fixture.ServiceProvider;
    }

    [Fact]
    public async Task Get_DepartmentById_Are_Equal()
    {
        using(var scope = _serviceProvider.CreateScope())
        {   
            // Arrange
            var context = scope.ServiceProvider.GetServices<SharedServicesContext>();
            context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
            context.SaveChanges();

            var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();

            // Act
            var departmentDto = await departmentAppService.GetDepartmentById(2);

            // Arrange
            Assert.Equal("123", departmentDto.DepartmentCode);           
        }
    }
}

在单元测试中使用依赖注入并不是一个好主意,你应该避免这种情况.顺便说一句,如果您不想重复自己注册依赖项,您可以将 DI 配置包装在另一个类中,并在您想要的任何地方使用该类.

Using dependency injection with unit test is not good idea and you should avoid that. by the way if you want don't repeat your self for registering dependencies, you can wrap your DI configuration in another class and use that class anywhere you want.

通过 Startup.cs 使用 DI:

public class IocConfig
{
    public static IServiceCollection Configure(IServiceCollection services, IConfiguration configuration)
    {
         serviceCollection
            .AddDbContext<SomeContext>(options => options.UseSqlServer(configuration["ConnectionString"]));
         serviceCollection.AddScoped<IDepartmentRepository, DepartmentRepository>();
         serviceCollection.AddScoped<IDepartmentAppService, DepartmentAppService>();
         .
         .
         .

         return services;
    }
}

Startup 类和ConfigureServices 方法中只使用IocConfig 类:

in Startup class and ConfigureServices method just useIocConfig class:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
         IocConfig.Configure(services, configuration);

         services.AddMvc();
         .
         .
         .

如果你不想使用IocConfig类,在Startup类中改变ConfigureServices:

if you don't want use IocConfig class, change ConfigureServices in Startup class:

public IServiceCollection ConfigureServices(IServiceCollection services)
{
     .
     .
     .
     return services;

并在测试项目中重用 IocConfigStartup 类:

and in test project reuse IocConfig or Startup class:

public class DependencySetupFixture
{
    public DependencySetupFixture()
    {
          var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", false, true));
         configuration = builder.Build();

         var services = new ServiceCollection();

         // services = IocConfig.Configure(services, configuration)
         // or
         // services = new Startup(configuration).ConfigureServices(services);

         ServiceProvider = services.BuildServiceProvider();
    }

    public ServiceProvider ServiceProvider { get; private set; }
}

在测试方法中:

[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
    using (var scope = _serviceProvider.CreateScope())
    {
        // Arrange
        var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();

        // Act
        var departmentDto = await departmentAppService.GetDepartmentById(2);

        // Arrange
        Assert.Equal("123", departmentDto.DepartmentCode);
    }
}

这篇关于Net Core:在 Xunit 测试中为 AppService、Repository 等执行所有依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆