SpecFlow 2.0, NUnit3, Visual Studio and TeamCity
We have recently upgraded our build environment to use SpecFlow 2.0, and NUnit3.
NUnit3 is supported by the latest build of TeamCity, and there is an NUnit3 Test Adapter for Visual Studio, but there are a few gotchas.
The first is to do with the base directory set by the NUnit Test Adapter in Visual Studio.
Unlike the previous version of the NUnit Runner, the current directory is set to the runner's installation directory, rather than the directory in which the tests are found.
Fortunately, NUnit3 provides TestContext.CurrentContext.TestDirectory
which helps a lot.
We've created a SpecFlow hook to change the current directory to the test directory for features that need it (e.g. when loading external support files)
[Binding]
public class NUnit3Hooks
{
[BeforeFeature("workingdirectory_feature")]
public static void ChangeWorkingDirectory()
{
FeatureContext.Current.Add("NUnit3Hooks.OldWorkingDirectory", Directory.GetCurrentDirectory());
Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory);
}
[AfterFeature("workingdirectory_feature")]
public static void RestoreWorkingDirectory()
{
Directory.SetCurrentDirectory(FeatureContext.Current.Get("NUnit3Hooks.OldWorkingDirectory"));
}
}
The second problem comes with executing the tests under TeamCity.
TC builds an NUnit project file to execute multiple test assemblies it discovers in your build. This is great - unless you are, for example, dynamically loading assemblies from the application base directory, as TC sets it to the root of the source checkout tree, rather than the directory executing the test assembly. (This is by design, and perfectly reasonable given the way NUnit executes multiple-assembly tests using the project file.)
However, it is no good if you want the individual test assemblies to be isolated, and loaded into their own AppDomain whose base directory is the test assembly location.
Fortunately, you can control how TC drives NUnit, by adding a build configuration parameter "nunit_use_project_file".
Edit your build configuration, select "Parameters" and add an additional parameter as in the image below.
If you set this to 'false' then TC doesn't build a project file, but passes the assemblies to NUnit on the command line. This causes NUnit to run them each in its own AppDomain, with the BaseDirectory set correctly.