XUnit DI through overridden Startup file (.net core)

流过昼夜 提交于 2019-12-01 06:53:18
Tseng

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

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
    }
}

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