TestServer & ASP.NET Core 5: Fix “System.InvalidOperationException : Solution root could not be located using application root” with a custom Startup file
I am very happy to write this post today because I have had a lot of trouble over the last few days getting my integration tests with TestServer to work on ASP.NET Core 5. I usually use a dedicated Startup.cs file to my integration tests rather than using the web application’s one.The simple good reason is that I do not like to replace instances of services or other configuration, I prefer a dedicated file for that. With each version of ASP.NET Core comes a change in the behavior of integration tests and in this post I will show you how to fix the external “System.InvalidOperationException : Solution root could not be located using application root” error when we use a Startup.cs file dedicated to our integration tests.
What’s happening ?
WebApplicationFactory class needs to infer the content root path and it’s doing it wrong if you proceed like this with a custom Startup.cs file for your tests when you create your own web factory:
This works perfectly with ASP.NET Core 3.1, but, with ASP.NET Core 5 you’ll run into that error: “System.InvalidOperationException : Solution root could not be located using application root”. TestServer confuses the integration test app and the web application.
To make it work with ASP.NET Core 5, you have to do 3 fixes:
- Go to you custom Startup.cs file in your integration test project and add the extension AddApplicationPart() on AddController() extension. This extension needs in parameter the application (to be tested) assembly to find all controllers and register them in the services collection. If you miss that step you’ll get 404 not found in your tests. Example:
- In your custom web factory, override the CreateHostBuilder() method instead of CreateWebHostBuilder() like in ASP.NET Core 3.1, the latter doesn’t not run with ASP.NET Core 5, it allows to create a IHost instead of a IWebHost which is not recommended to be used anymore. Then add the extension method on the builder UseStartup<T>() and use your custom Startup.cs file as the EntryPoint of your integration test app.
- In the same custom web factory, when you inherit from WebApplicationFactory, instead passing as generic your custom Startup file, pass any class of your application to be tested. It is only used for reflection purpose (while the WebApplicationFactory tries to infer the application’s content root). Example:
If you now use your custom factory to make integration tests with ASP.NET Core 5, it should work like a charm 😉