I'm am trying to create integration tests of the controller, but I need to mock some of the dependencies registered in Startup class. Currently the only possible option of customisation is via call builder.ConfigureServices inside overriden method ConfigureWebHost.
However, if the set of mocked dependencies changes from test to test it requires creation of multiple descendants of WebApplicationFactory<TStartup>.
There is one more problem. I use SimpleInjector DI container which is stored in property Container of Startup class. It means I have to access Startup class in order to configure registrations of mocks. (I don't want to expose Container as a static property as it brings potential problems with parallel test runs.)
I would like WebApplicationFactory<TStartup> class to have constructor with this signature and corresponding behaviour:
public WebApplicationFactory<TStartup>(
Action<IServiceCollection, TStartup> configureServices)
Thanks for contacting us, @voroninp.
@javiercn, do you have any thoughts regarding this ask?
I鈥檇 ask for one more option. You use TStartup for searching the project and I may need to inherit from it to further adjust startup behavior. Would be nice to have this option as well without losing correct path resolution if type of descendant is used as generic argument.
We don't use TStartup to find the project, we use a type on the app assembly, which by convention is startup, but you can use Program and use a custom startup and that should work.
So
CustomWAF<TCustomStartup> : WAF<Program>
{
override ConfigureWebHost(IWebHostBuilder builder) => builder.UseStartup<TCustomStartup>
}
Also there is a method on the WebApplicationFactory WithWebHostBuilder that will create a child factory with your customizations for one off configuration changes.
For simple injector, I'm not sure how it integrates with ASP.NET Core but we have a ConfigureTestContainer<TContainer> helper method that you can call to configure it. Provided that simple injector overrides the DI container factory.
If not, you can derive from startup and configure the container in the derived class or register the container instance in the asp.net core service collection, and use ConfigureTestServices to retrieve the container from the collection and configure it. (This is a bit hacky, but there are limited options here).
Otherwise, there's nothing else I can think we can do.
Closing as the question has been answered.
@javiercn Yes, inheriting seems to be the only option as SI does not override the factory.
@javiercn BTW, how do I get the instance of CustomStartup? =)
@voroninp You need to hack around this I think.
Create CustomStartup and override ConfigureServices (make it virtual on Startup) and simply register your startup as a singleton in the service collection.
override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);
services.TryAddSingleton(this);
}
Then on your tests.
factory.WithWebHostBuilder(builder => builder.ConfigureTestServices(services => {
var startup = services.Single(s => s.ServiceType == typeof(CustomStartup);
// Party on
}));
This should do it, if not, I'm out of ideas here.
@javiercn Or just register in regular startup's ConfigureServices: services.AddSingleton(this.GetType(), this);
This will work for the inherited class as well.
Not sure, but should not this happen automatically? ;-)
@voroninp I was being more tricky so that you don't have to register your startup class on the DI container in the normal flow. It should be pretty harmless, but there's no need to have that for your app just to run and is a distraction IMO.
No, in a normal scenario I can't think why would you want your startup class registered in DI (other than testing, which can be achieved entirely on the test assembly)