通过覆盖的启动文件(.net核心)的XUnit DI [英] XUnit DI through overridden Startup file (.net core)

查看:123
本文介绍了通过覆盖的启动文件(.net核心)的XUnit DI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经构建了一个WebAPI,除了我在Postman上运行的测试之外,我还想实现一些集成/单元测试.

I have build a WebAPI and apart from my tests running on Postman I would like to implement some Integration/Unit tests.

现在,我的业务逻辑非常薄,大多数情况下,它的CRUD操作更多,因此我想从测试我的Controllers开始.

Now my business logic is very thin, most of the time its more of CRUD actions, therefore I wanted to start with testing my Controllers.

我有一个基本设置.存储库模式(接口),服务(业务逻辑)和控制器. 流程进入控制器(DI服务)->服务(DI回购)->回购操作!

I have a basic setup. Repository pattern (interfaces), Services (business logic) and Controllers. The flow goes Controller (DI Service) -> Service (DI Repo) -> Repo Action!

所以我所做的是重写我的启动文件以将其更改为内存数据库,其余的应该没问题(我会假设),添加了服务,添加了回购协议,现在我指向的是内存数据库,这很好用于我的基本测试.

So what I did was override my Startup file to change into a in memory database and the rest should be fine (I would assume) Services are added, repos are added and now I am pointing into a in memory DB which is fine for my basic testing.

namespace API.UnitTests
{    
    public class TestStartup : Startup
    {
        public TestStartup(IHostingEnvironment env)
            : base(env)
        {

        }

        public void ConfigureTestServices(IServiceCollection services)
        {
            base.ConfigureServices(services);
            //services.Replace<IService, IMockedService>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            base.Configure(app, env, loggerFactory);
        }

        public override void SetUpDataBase(IServiceCollection services)
        {
            var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = ":memory:" };
            var connectionString = connectionStringBuilder.ToString();
            var connection = new SqliteConnection(connectionString);

            services
                .AddEntityFrameworkSqlite()
                .AddDbContext<ApplicationDbContext>(
                    options => options.UseSqlite(connection)
                );
        }
    }
}

我写了我的第一个测试,但是不存在DatasourceService:

I wrote my first test, but the DatasourceService is not there:

以下构造函数参数没有匹配的灯具数据:DatasourceService datasourceService

The following constructor parameters did not have matching fixture data: DatasourceService datasourceService

namespace API.UnitTests
{
    public class DatasourceControllerTest
    {
        private readonly DatasourceService _datasourceService; 

        public DatasourceControllerTest(DatasourceService datasourceService)
        { 
            _datasourceService = datasourceService;            
        }

        [Xunit.Theory,
        InlineData(1)]
        public void GetAll(int companyFk) {
            Assert.NotEmpty(_datasourceService.GetAll(companyFk));
        }
    }
}

我想念什么?

推荐答案

您不能在测试类上使用依赖项注入.您只能让xunit通过构造函数注入特殊的夹具(请参见 docs ).

You can't use dependency injection on test classes. You can only let xunit inject special fixtures via constructor (see docs).

对于集成测试,您想使用Microsoft.AspNetCore.TestHost包中的TestServer类和一个单独的Startup.cs类(比继承imho更容易设置配置).

For Integration Testing you want to use the TestServer class from Microsoft.AspNetCore.TestHost package and a separate Startup.cs class (easier to setup configuration than inheritance imho).

public class TestStartup : Startup
{
    public TestStartup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureTestServices(IServiceCollection services)
    {
        services.Replace(ServiceDescriptor.Scoped<IService, MockedService>());
        services.AddEntityFrameworkSqlite()
            .AddDbContext<ApplicationDbContext>(
                options => options.UseSqlite(connection)
            );
    }

    public void Configure(IApplicationBuilder app)
    {
        // your usual registrations there
    }
}

在单元测试项目中,您需要创建TestServer的实例并执行测试.

In your unit test project, you need to create an instance of the TestServer and perform the test.

public class DatasourceControllerTest
{
    private readonly TestServer _server; 
    private readonly HttpClient _client;

    public DatasourceControllerTest()
    {
        // Arrange
        _server = new TestServer(new WebHostBuilder()
            .UseStartup<TestStartup>());
        _client = _server.CreateClient();
    }

    [Xunit.Theory,
    InlineData(1)]
    public async Task GetAll(int companyFk) {
        // Act
        var response = await _client.GetAsync($"/api/datasource/{companyFk}");
        // expected result from rest service
        var expected = @"[{""data"":""value1"", ""data2"":""value2""}]";

        // Assert
        // This makes sure, you return a success http code back in case of 4xx status codes 
        // or exceptions (5xx codes) it throws an exception
        response.EnsureSuccessStatusCode();

        var resultString = await response.Content.ReadAsStringAsync();
        Assert.Equals(resultString, expectedString);
    }
}

现在,当您调用写入数据库的操作时,您还可以检查数据是否确实写入了数据库:

Now, when you call operations which write to the database, you can also check if the data is really written to the database:

[Xunit.Theory,
InlineData(1)]
public async Task GetAll(int companyFk) {
    // Act
    var response = await _client.DeleteAsync($"/api/datasource/{companyFk}");
    // expected result from rest service

    // Assert
    response.EnsureSuccessStatusCode();

    // now check if its really gone in the database. For this you need an instance 
    // of the in memory Sqlite DB. TestServer has a property Host, which is an IWebHost
    // and it has a property Services which is the IoC container

    var provider = _server.Host.Services;
    var dbContext = provider.GetRequiredService<ApplicationDbContext>();

    var result = await dbContext.YourTable.Where(entity => entity.Id == companyFk).Any();

    // if it was deleted, the query should result in false
    Assert.False(result);
}

这篇关于通过覆盖的启动文件(.net核心)的XUnit DI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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