在测试中,我必须有权访问数据库上下文(真实数据库,它不在内存中)。因为发布后,我想确保记录已保存在数据库中。
这就是我所拥有的,它可以完美运行,但是我没有足够的经验来确保这是获取上下文的正确方法。
public class ValuesControllerTests : TestHostFixture
{
[Theory]
[InlineData("/values/sample")]
public async Task Sample_WhenCreatingSampleData_ThenIsAddedToDatabase(string url)
{
// given
var command = new AddSampleCommand { Name = "TestRecord" };
// when
var httpResponse = await Client.PostAsJsonAsync(url, command);
// then
httpResponse.EnsureSuccessStatusCode();
using (var dbContext = GetContext())
{
dbContext.Samples.FirstOrDefault(x => x.Name == "TestRecord").ShouldNotBeNull();
}
}
}
public abstract class TestHostFixture : IClassFixture<CustomWebApplicationFactory<Startup>>
{
protected readonly HttpClient Client;
private readonly CustomWebApplicationFactory<Startup> _factory;
protected TestHostFixture()
{
_factory = new CustomWebApplicationFactory<Startup>();
Client = _factory.CreateClient();
}
protected MyContext GetContext()
{
return _factory.Server.Host.Services.CreateScope().ServiceProvider.GetService<MyContext>();
}
}
因此,总而言之-在测试中,我通过以下方式获取上下文:
using (var dbContext = GetContext())
{
dbContext.Samples.FirstOrDefault(x => x.Name == "TestRecord").ShouldNotBeNull();
}
和GetContext方法:
protected MyContext GetContext()
{
return _factory.Server.Host.Services.CreateScope().ServiceProvider.GetService<MyContext>();
}
请让我知道这是否可以,或者由于将来可能出现的问题,我应该以某种方式进行重构。
答案 0 :(得分:1)
通常,这很好:您绝对应该利用主机的DI容器来检索数据库上下文。由于数据库上下文是作用域的,因此创建新的服务范围来检索上下文也是正确的。
但是,由于通常由DI容器管理它创建的对象的生存期,因此应该将处理数据库上下文的工作留给DI容器,而不是服务范围。
尽管在单元测试中可能没有多大关系,但是无论如何它都会很快被清除(并且由于您正在处理上下文,因此您也不会泄漏数据库连接),但从长远来看,它仍然是更好的样式和更安全的方法运行。
因此,请处置服务范围:
// …
httpResponse.EnsureSuccessStatusCode();
using (var scope = Host.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<MyContext>();
var item = dbContext.Samples.FirstOrDefault(x => x.Name == "TestRecord");
item.ShouldNotBeNull();
}
答案 1 :(得分:0)
在对poke提供的实现进行改进的情况下,您可以考虑创建一个委托来处理对所创建范围的正确处理。
例如
protected void GetContext(Action<MyContext> test) {
using(var scope = _factory.Server.Host.Services.CreateScope()) {
var context = scope.ServiceProvider.GetRequiredService<MyContext>();
test(context);
}
}
在进行测试时,只需致电代表
[Theory]
[InlineData("/values/sample")]
public async Task Sample_WhenCreatingSampleData_ThenIsAddedToDatabase(string url) {
// given
var command = new AddSampleCommand { Name = "TestRecord" };
// when
var httpResponse = await Client.PostAsJsonAsync(url, command);
// then
httpResponse.EnsureSuccessStatusCode();
GetContext(dbContext => {
var item = dbContext.Samples.FirstOrDefault(x => x.Name == "TestRecord");
item.ShouldNotBeNull();
});
}