WebApplicationFactory
(TL;DR -- here's the source code on GitHub)
Testing Tricks with WebApplicationFactory
What do I mean by "handy testing tricks"? The handiest of handy testing tricks is simply just turning off security during your tests. You'd never do this in production but when you're writing automated integration tests against your ASP.NET Core apps, you usually just want to focus on feature functionality in your application. So if you have to worry about coding all the "log into the app" test code in addition to testing the feature functionality -- well, if you're like most devs, you'll say "that feels like a whole lot of work" and then not write the test. With integration tests that are written with WebApplicationFactory
Here's the basic idea. If you're using dependency injection to configure your dependencies in Startup.cs for production, what WebApplicationFactory
Selenium & WebApplicationFactory
What about running Selenium tests using WebApplicationFactory
OpenQA.Selenium.WebDriverException: unknown error: net::ERR_CONNECTION_REFUSED (Session info: headless MicrosoftEdge=91.0.864.70) Stack Trace: at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse) at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters) at OpenQA.Selenium.Remote.RemoteWebDriver.set_Url(String value) at OpenQA.Selenium.Remote.RemoteNavigator.GoToUrl(String url)
I worked for HOURS and HOURS on this error and didn't make a whole lot of progress. But then I found a couple of blog posts that started to clear things up for me:
- "Real Browser Integration Testing with Selenium Standalone, Chrome, and ASP.NET Core 2.1" by Scott Hanselman
- "Quick fix for integration testing with Selenium in ASP.NET Core 3.1" by Bertrand Thomas
What's Going Wrong?
The core of the problem is related to how integration tests work with WebApplicationFactory
WHY!?!?!?!?!?!?!?!
Well, under the surface, that call to WebApplicationFactory
How to Fix It?
This is where Bertrand Thomas's blog post helped out immensely. He figured out that you needed to make a separate call to spin up an instance of TestServer in order to make your application respond to HTTP requests coming over the network. (High five, Bertrand! 🙌)
Bertrand's solution is to use a custom version of WebApplicationFactory
Where Stuff Starts Getting Weird
Like I mentioned earlier in this article, when I do integration tests with WebApplicationFactory
Turns out that when you make the calls to create an instance of TestServer, that what you're doing is starting up a *SECOND* instance of your application! Ahhhhhhh. So all my type replacements were happening in one instance of my app but not the other instance.
The Solution
In the end, I ended up creating my own version of WebApplicationFactory
The CustomWebApplicationFactory
Summary
Initialize the System Under Test using our custom WebApplicationFactory
The source code for this is available at Github. There's a very simple ASP.NET Core MVC web app that I use to test again. Then there are a handful of tests in IntegrationTestFixtures.cs. The logic for loading WebApplicationFactory
I hope this helps.
-Ben