Setup
Description
I'm using the WebApplicationFactory
from the Microsoft.AspNetCore.Mvc.Testing
package to setup my integration tests.
I've been following the official documentation to customise the web host configuration.
The SUT uses Dapper to query from the database, so I'm not using the In-Memory provider that ships with EF Core for this particular integration test.
My code for setting up the WebApplictionFactory
is below:
public class CustomWebApplicationFactory<TStartup>
: WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder
.UseStartup<TStartup>()
.ConfigureServices(services =>
{
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database context
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var dbContext = scopedServices.GetRequiredService<MyDbContext>(); // <-- service not found
dbContext.Database.EnsureCreated();
new MyDbContextSeed()
.SeedAsync(dbContext)
.Wait();
}
});
}
}
Issue
The MyDbContext
service isn't found, I understand why (I think) - because the ServiceProvider
from my Startup.cs
class hasn't built yet.
But the question is How can I access the services from my Startup class here?
For context, the Integration test looks like this:
public class MyAPITests
: IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
private readonly CustomWebApplicationFactory<Startup> _factory;
public MyAPITests(CustomWebApplicationFactory<Startup> factory)
{
_factory = factory;
_client = factory.CreateClient();
}
[Fact]
public async Task Get_ItemAsync_WhenIdNotFound_ReturnsNotFoundStatusCode()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Get, "api/v1/item/0");
// Act
var response = await _client.SendAsync(request);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
}
First, ConfigureServices
can be used instead of UseStartup
, not together. Second, you shouldn't create the scope and do the migration during ConfigureServices
anyways, but rather after the Web Host is built, see here :
In older tutorials, you may see similar code in the
Configure
method in Startup.cs. We recommend that you use the Configure method only to set up the request pipeline. Application startup code belongs in theMain
method.
The only way to do this is not in the factory, but after the factory built it:
public class MyAPITests
: IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
private readonly CustomWebApplicationFactory<Startup> _factory;
public MyAPITests(CustomWebApplicationFactory<Startup> factory)
{
_factory = factory;
_client = factory.CreateClient();
var host = factory.Server.Host;
using (var scope = host.Services.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var dbContext = scopedServices.GetRequiredService<MyDbContext>();
dbContext.Database.EnsureCreated();
new MyDbContextSeed()
.SeedAsync(dbContext)
.Wait();
}
}
//...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.