I've updated my website with .Net Core 3.0 preview 2 and I want to make Integration Test with a TestServer. In .Net Core 2.2, I've been able to make it using WebApplicationFactory<Startup>
Since WebHostBuilder
is about to be deprecated (see (https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-2.2&tabs=visual-studio) for more details.), I want to follow up and implement the new Generic HostBuilder
now. It is working great for launching the website but it crashes when I launch my Integration tests. I know that WebApplicationFactory
does use WebHostBuilder
and that's why it's crashing, but I don't know how to change it for the Generic HostBuilder
.
Here is my code that was working in .Net Core 2.2 :
namespace CompX.FunctionalTest.Web.Factory
{
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Create a new service provider.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Add a database context (ApplicationDbContext) using an in-memory
// database for testing.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
options.UseInternalServiceProvider(serviceProvider);
});
services.AddDbContext<AppIdentityDbContext>(options =>
{
options.UseInMemoryDatabase("Identity");
options.UseInternalServiceProvider(serviceProvider);
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database
// context (ApplicationDbContext).
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<ApplicationDbContext>();
var loggerFactory = scopedServices.GetRequiredService<ILoggerFactory>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
// Ensure the database is created.
db.Database.EnsureCreated();
try
{
// Seed the database with test data.
var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>();
AppIdentityDbContextSeed.SeedAsync(userManager).GetAwaiter().GetResult();
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with test messages. Error: {ex.Message}");
}
}
});
}
}
}
I tried with TestServers
from Microsoft.AspNetCore.TestHost
, but it needs new WebHostBuilder()
as parameters.
I also tried to pass this as parameters, but it didn't work as well :
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
It can't find the .ConfigureWebHostDefaults()
function.
Did anyone successfuly implemented a Test server in .Net Core 3.0 ? Thanks a lot !
PS : I'm kinda new to .Net Core
EDIT :
That's the error that I get from all the methods that try to make a new server :
Here is the program.cs
namespace CompX.Web
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Here is the issue that I've created on github : https://github.com/aspnet/AspNetCore/issues/7754
I finally got how to do it in 3.0. Here's the full walkthrough on how to do it for anyone that needs the solution :
You need to have atleast .Net Core 3.0.0-preview2, since they added the WebApplicationFactory
with IHostbuilder
in this preview (https://github.com/aspnet/AspNetCore/pull/6585). You can find it here : https://dotnet.microsoft.com/download/dotnet-core/3.0
Upgrade atleast theses packages to version 3.0.0 (https://github.com/aspnet/AspNetCore/issues/3756 and https://github.com/aspnet/AspNetCore/issues/3755):
Microsoft.AspNetCore.App Version=3.0.0-preview-19075-0444
Microsoft.AspNetCore.Mvc.Testing Version= 3.0.0-preview-19075-0444
Microsoft.Extensions.Hosting Version=3.0.0-preview.19074.2
Remove now deprecated packages that are now included in Microsoft.AspNetCore.App
:
Microsoft.AspNetCore Version=2.2.0
Microsoft.AspNetCore.CookiePolicy Version=2.2.0
Microsoft.AspNetCore.HttpsPolicy Version=2.2.0
Microsoft.AspNetCore.Identity Version=2.2.0
If your were using services.AddIdentity
in your WebApplicationFactory<Startup>
builder, you'll need to delete it. Otherwise, you'll have a new error saying that you have already use that scheme for Identity.Application
. It looks like the new WebApplicationFactory
is using the one from Startup.cs
now.
I had nothing else to modify. Hope it will be helpful for some people !
Update :
It was working well until I had to use another Integration C# file (e.g LoginTest.cs
and ManageTest.cs
). The problem was that when I ran my test, it would infinitly loop until I pressed CTRL + C.
After that, it would display an Access Denied error.
Once again, I had to remove something from my WebApplicationFactory
, the seeds :
try
{
// Seed the database with test data.
var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>();
AppIdentityDbContextSeed.SeedAsync(userManager).GetAwaiter().GetResult();
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with test messages. Error: {ex.Message}");
}
It looks like the new WebApplicationFactory
was trying to recreate the usermanager for each factories. I replaced my seeded user accounts with Guid.NewGuid().
Took me a while to figure it out. Hope it might help someone, once again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With