简体   繁体   English

如何使用TestServer和数据种子类在内存数据库中共享以在内存中运行集成测试

[英]How to share in memory database using TestServer and data seeding class to run Integration Tests in memory

I recently started using TestServer class to self-host and bootstrap an Aspnet Core API to run Integration Tests without a dedicated running environment. 我最近开始使用TestServer类自托管和引导Aspnet Core API,以在没有专用运行环境的情况下运行集成测试

I love the way it works and using custom environment name, I decided to control the way the EF Context is created, switching from SQL Server to In-Memory database. 我喜欢它的工作方式,并使用自定义环境名称,因此决定控制EF上下文的创建方式,从SQL Server切换到内存数据库。

Problem is that in order to seed the data necessary to run the tests via API requests, would be very expensive for both coding and running time. 问题是,为了通过API请求播种运行测试所需的数据,这对于编码和运行时间都非常昂贵。

My idea is to create a class or a simple framework to seed the data necessary by each test, but to do so I need to use the same in-memory database which is initialized with the API stack by the TestServer . 我的想法是创建一个类或一个简单的框架来播种每个测试所需的数据,但为此,我需要使用相同的内存数据库,该数据库由TestServer使用API​​堆栈初始化。

How is it possible to do so? 怎么可能呢?

In the first place is important to understand that for better testing in replacement to a relational database such SQL Server, In Memory database is not ideal. 首先,重要的是要了解,为了更好地测试替换关系数据库(例如SQL Server), “内存”数据库并不是理想的选择。

Among the various limitations, it does not support foreign key constraints. 在各种限制中,它不支持外键约束。 A better way to use an in-memory database is to use SQLite In-Memory mode . 使用内存数据库的更好方法是使用SQLite内存模式

Here is the code I used to setup the TestServer, Seed the Data and register the DB Context for the Dependency Injection: 这是我用于设置TestServer,为数据添加种子并为依赖项注入注册数据库上下文的代码:

TestServer 测试服务器

public class ApiClient {
    private HttpClient _client;

    public ApiClient()
    {
        var webHostBuilder = new WebHostBuilder();
        webHostBuilder.UseEnvironment("Test");
        webHostBuilder.UseStartup<Startup>();
        var server = new TestServer(webHostBuilder);
        _client = server.CreateClient();
    }

    public async Task<HttpResponseMessage> PostAsync<T>(string url, T entity)
    {
        var content = new StringContent(JsonConvert.SerializeObject(entity), Encoding.UTF8, "application/json");
        return await _client.PostAsync(url, content);
    }

    public async Task<T> GetAsync<T>(string url)
    {
        var response = await _client.GetAsync(url);
        response.EnsureSuccessStatusCode();
        var responseString = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseString);
    }
}

Data Seeding (Helper class) 数据种子(Helper类)

public class TestDataConfiguration
{
    public static IMyContext GetContex()
    {
        var serviceCollection = new ServiceCollection();
        IocConfig.RegisterContext(serviceCollection, "", null);
        var serviceProvider = serviceCollection.BuildServiceProvider();
        return serviceProvider.GetService<IMyContext>();
    }
}

Data Seeding (Test class) 数据播种(测试类)

[TestInitialize]
public void TestInitialize()
{
    _client = new ApiClient();
    var context = TestDataConfiguration.GetContex();
    var category = new Category
    {
        Active = true,
        Description = "D",
        Name = "N"
    };
    context.Categories.Add(category);
    context.SaveChanges();
    var transaction = new Transaction
    {
        CategoryId = category.Id,
        Credit = 1,
        Description = "A",
        Recorded = DateTime.Now
    };
    context.Transactions.Add(transaction);
    context.SaveChanges();
}

DB Context registration (In IocConfig.cs) 数据库上下文注册(在IocConfig.cs中)

public static void RegisterContext(IServiceCollection services, string connectionString, IHostingEnvironment hostingEnvironment)
{
    if (connectionString == null)
        throw new ArgumentNullException(nameof(connectionString));
    if (services == null)
        throw new ArgumentNullException(nameof(services));

    services.AddDbContext<MyContext>(options =>
    {
        if (hostingEnvironment == null || hostingEnvironment.IsTesting())
        {
            var connection = new SqliteConnection("DataSource='file::memory:?cache=shared'");
            connection.Open();
            options.UseSqlite(connection);
            options.UseLoggerFactory(MyLoggerFactory);
        }
        else
        {
            options.UseSqlServer(connectionString);
            options.UseLoggerFactory(MyLoggerFactory);
        }
    });

    if (hostingEnvironment == null || hostingEnvironment.IsTesting())
    {
        services.AddSingleton<IMyContext>(service =>
        {
            var context = service.GetService<MyContext>();
            context.Database.EnsureCreated();
            return context;
        });
    } else {
        services.AddTransient<IMyContext>(service => service.GetService<MyContext>());
    }
 }

The key is the URI file string used to create the SQLite connection: var connection = new SqliteConnection("DataSource='file::memory:?cache=shared'"); 关键是用于创建SQLite连接的URI文件字符串var connection = new SqliteConnection("DataSource='file::memory:?cache=shared'");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在集成测试之间重置 In-Memory 数据库 - Resetting In-Memory database between integration tests 如何使用TestServer和Antiforgery修复POST集成测试中的500 Internal Server Error? ASP.NET核心 - How to fix 500 Internal Server Error for POST integration tests using TestServer and Antiforgery? ASP.NET Core 使用Visual Studio Team Services通过内存中的SQL数据库运行单元/集成测试 - Running Unit / Integration tests through an in-memory SQL database using Visual Studio Team Services 最小的 Web API 和播种内存中实体框架数据库 - Minimal Web API and seeding an in-memory Entity Framework database EF Core In Memory 数据库数据在单元测试之间泄漏 - EF Core In Memory database data leaking between unit tests 不使用数据库的内存中类 - In-Memory class without using database C# 无法访问为集成测试创建的内存数据库 - C# can't access an in-memory database created for integration tests 集成测试-数据库中的设置数据 - Integration tests - Setup data in database Dotnetcore 3.1 中间件 HttpContext.Request 在内存中 TestServer 集成测试期间运行中间件之前已经为空 - Dotnetcore 3.1 middleware HttpContext.Request is already null before middleware runs during in-memory TestServer integration test 单元测试与集成测试:实体框架核心在内存中 - Unit Tests vs Integration tests: Entity Framework Core In memory
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM