27

I want to set up my tests using WebApplicationFactory<T> as detailed in Integration tests in ASP.NET Core.

Before some of my tests I need to use a service configured in the real Startup class to set things up. The problem I have is that I can't see a way to get a service from the factory.

I could get a service from factory.Server using factory.Host.Services.GetRequiredService<ITheType>(); except that factory.Server is null until factory.CreateClient(); has been called.

Is there any way that I am missing to get a service using the factory?

Thanks.

Simon Vane
  • 1,686
  • 2
  • 17
  • 21
  • Wouldn't the startup used for the test be able to register and use the service? Show what you have so far in what you are trying to do – Nkosi Oct 10 '18 at 17:09
  • Or you could customize the factory https://docs.microsoft.com/en-gb/aspnet/core/test/integration-tests?view=aspnetcore-2.1#customize-webapplicationfactory – Nkosi Oct 10 '18 at 17:10
  • Thanks @Nkosi. I need to get a service that's registered in the real Startup rather than the test Startup. I want to run a test using the fully configured application so I need to get the real service, call a couple of methods to setup some data, then run my test scenario. I need to be able to get this service in each test. – Simon Vane Oct 10 '18 at 17:14
  • create a test startup that inherits from real startup. override configureservices, call base, build provider get service and perform setup – Nkosi Oct 10 '18 at 17:17
  • If I can see some code, I could probably provide a more detailed explanation. – Nkosi Oct 10 '18 at 17:17
  • OK, thanks a lot @Nkosi, I'll create a minimal example. – Simon Vane Oct 10 '18 at 18:20
  • Thanks for your offer @Nkosi. Apologies for not getting an example to you. – Simon Vane Jan 18 '19 at 12:41
  • No worries. Glad to see you got a solution provided. – Nkosi Jan 18 '19 at 12:45

2 Answers2

29

You need to create a scope from service provider to get necessary service:

using (var scope = AppFactory.Server.Host.Services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<MyDatabaseContext>();
}
13

Please pardon me. I know you ask for Net Core 2.1, but since v3.1+ people got here as well...

My project uses Net Core 3.1. When I use AppFactory.Server.Host.Services.CreateScope() like Alexey Starchikov's suggestion, I encounter this error.

The TestServer constructor was not called with a IWebHostBuilder so IWebHost is not available.

Noted here, by designs.

So I use the below approach. I put database seeding in the constructor of the test class. Note that, I do not have to call factory.CreateClient(). I create client variables in test methods as usual.

using (var scope = this.factory.Services.CreateScope())
{
    var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>();

    // Seeding ...

    dbContext.SaveChanges();
}
Lam Le
  • 740
  • 8
  • 22