4

I am running into an issue where I am using a custom WebApplicationFactory and it is not registering the services in my Startup.cs. I am using Asp.Net core 3.1 and Xunit.

I have below in my API (startup.cs) registered using extension methods:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddBaseApiConfiguration(Configuration);

            services.AddRepositoryServices();

            services.AddApiServices();

            services.AddMediatrServices();
        }

Per MS documentation:

The SUT's database context is registered in its Startup.ConfigureServices method. The test app's builder.ConfigureServices callback is executed after the app's Startup.ConfigureServices code is executed.

But above is not occurring. None of my services from the startup I am using are being registered (i.e. the 4 extension methods I have are never being called and are never registered). This is causing a few problems: my DB context uses IMediatr in its constructor so that events can be published during context.SaveChangesAsync() (on success). But as my service is never registered, it fails to find it. How do I ensure that this takes place correctly?

Below is my custom factory:

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder
        .UseEnvironment("Development")
        .ConfigureServices(services =>
        {
            // Remove the app's db context registrations
            var descriptor = services.SingleOrDefault(
                d => d.ServiceType ==
                    typeof(DbContextOptions<AppDbContext>));


            if (descriptor != null)
            {
                services.Remove(descriptor );
            }

            services.AddSingleton<IDbConnectionFactoryService, SqliteConnectionFactoryService>();

            // Add a database context using an in-memory 
            // database for testing.
            services.AddDbContext<AppDbContext>(options =>
            {
                options.UseSqlite("Data Source=sqlitedemo.db");
            });

            // Build the service provider.
            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 db = scopedServices.GetRequiredService<AppDbContext>();

                // Ensure the database is created.
                db .Database.EnsureDeleted();
                db .Database.EnsureCreated();
            }
        });
    }

Edit: It seems the services in Startup.cs are being called after the CustomWebApplication factory services. This is completely odd as per .Net core 3.0, the order was changed to be the opposite. So why is this still occuring?

Edit 2: Need to use ConfigureTestServices instead of ConfigureServices.

2 Answers 2

2

I didn't find this in the docs but calling ConfigureTestServices ensures that the CustomWebApplicationFactory services are called after Startup services are called. Per the docs, this is not pointed out correctly but at least this might help someone else who ran into the same issue.

Sign up to request clarification or add additional context in comments.

1 Comment

This still isn't in the MS documentation though is absolutely critical
0

If you have just a few integration tests with common mock service registrations, ConfigureTestServices works just fine, but it doesn’t scale well when many tests need their own specific mock registrations. ConfigureTestServices requires that you rebuild the host and its DI container for each case. I developed an extension to Microsoft Dependency Injection that allows local mocks without rebuilding the container. Check it out - Rsi.DependencyInjection.

2 Comments

This is pretty handy. I'll check it out if I have a lot of services but I went down the route of using xunit collection fixture to not have to spin up a new instance of the container.
I use the same technique with XUnit, but you won’t be able to reuse the test host in different tests if those tests need different sets of mock registrations. ConfigureTestServices requires rebuilding the host, so you’ll have to use different collection fixture for different mocks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.