Endjin - Home

SpecFlow 2.0, NUnit3, Visual Studio and TeamCity

by Matthew Adams

header-specflow-nunit-vs-tc-p1-1024px

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.

BuildConfigSettingsParameters

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.

About the author

Matthew was CTO of a venture-backed technology start-up in the UK & US for 10 years, and is now a Founder of Endjin Ltd, which provides technology strategy, experience and development services to its clients who are seeking to take advantage of Microsoft Azure and the Cloud. You can follow Matthew on twitter.