I develop integration tests in .NET Core. Because controllers have multiple dependencies it's inconvenient to create their instances manually. Here's how I create ServiceProvider instance to be able to access .NET Core native DI container:
HostingEnvironment env = new HostingEnvironment();
env.ContentRootPath = Directory.GetCurrentDirectory();
env.EnvironmentName = "Development";
Startup startup = new Startup(env);
ServiceCollection sc = new ServiceCollection();
startup.ConfigureServices(sc);
ServiceProvider = sc.BuildServiceProvider();
Startup class is taken from tested assembly.
To my surprise service provider is unable to create instances of controllers. It can instantiate registered services, but not the controllers. Does anybody have any idea why it is so?
You should use TestServer, which bootstraps a complete test environment (optionally using a different startup class or environment variable, where you can replace data store with an in-memory store).
The ASP.NET Core documentation covers this case quite well.
var server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
// this would cause it to use StartupIntegrationTest or ConfigureServicesIntegrationTest / ConfigureIntegrationTest methods (if existing)
// rather than Startup, ConfigureServices and Configure
.UseEnvironment("IntegrationTest"));
In these alternative/environment-dependent methods you can put your integration test specific replacements/DI configuration.
Second, controllers (and tag helpers and view components) are not registered with the DI system by default. The controller factories will resolve the types. If you want that the controllers to get resolved via built-in or 3rd party IoC containers, you have to tell ASP.NET Core to register them explicitly (see this related question).
Here is an example:
services
.AddMvc()
.AddControllersAsServices()
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
I would recommend you to use the first approach, as it's more consistent and exactly the reason the Startup class with environment support is there.
Important addition. If you use the TestServer, you can also access its DI Container (IServiceProvider instance).
var server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment("IntegrationTest"));
var controller = server.Host.Services.GetService<MyController>();
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