[英]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.