14
votes

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 : enter image description here

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

1
Can you show your Program.cs file?Kalten
Sure, i'll add it in the edit.Fearware
The test factory is waiting for an iwebhostbuilder but you use an ihostbuilder instead. I'm not sure this is currently supported. As there are lot of changes happening on theses API. Need to check aspnet source code ...Kalten
Ok thanks, If I don't get an answer from Stack, I might go ask directly on the aspnet core github if they added this feature.Fearware
I quickly checked the source code and everything use the iwebhostbuilder version. github.com/aspnet/AspNetCore/blob/master/src/Hosting/TestHost/…Kalten

1 Answers

5
votes

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 :

  1. 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

  2. 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
  3. 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
  4. 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.