We are using the Owin Test Server in our codebase to run boundary tests against our API instance. We have the following line of code within a fixture, and the fixture is used across multiple tests. The tests are written using XBehave, which is backed by XUnit 2.
public TestServer Server { get; } = TestServer.Create<Startup>();
The Startup.cs is from our API project. This subsequently registers the routes, which causes the following exception:
System.ArgumentException: A route named 'Default' is already in the route collection. Route names must be unique.
Every single API test fails that uses this fixture, across 9 different test classes.
If I make the Server variable static within the fixture then this problem goes away, however everything I have read makes me feel this shouldn't even be happening?
Can someone give me some guidance about what might be causing this issue?
My first thought is that these routes may be stored statically, so recreating them may be giving the duplication error. The tests would thus be state/sequence dependent. It should be possible to analyse this behaviour by debugging multiple tests within the same execution run, and examining how the later tests in the run behave around this state.
NCrunch has a few differences in how it executes tests inside the test application domain. If you haven't already, it's worth becoming familiar with these differences as they can sometimes trip up tests on subtle ways. See here for more information - http://www.ncrunch.net/documentation/considerations-and-constraints_test-atomicity.
Thanks for getting back to me. Your response pointed me to the right direction. The cause is the reuse of the test runner process across tests.
The Startup class had a static call to RouteTable.Routes. I introduce a new derived class from Startup and made the call to get the routes a virtual method, returning RouteTable.Routes in the Startup class, and a new RouteCollection in my TestStartup class when any routes were found. This is because the presence of any routes meant the static config had already been set up.
The result is code introduced just for NCrunch, but its footprint is lightweight and it's an acceptable pattern to my mind.