Nunit: Working directory for tests in console NUnit 3

Created on 26 Nov 2015  ·  21Comments  ·  Source: nunit/nunit

In NUnit 2.6.4, working dir for my tests was set to corresponding bin/Debug directory of test DLL. This allowed me to load external files in tests by relative path.

It seems that now working dir is set to the working directory of console runner. Is this by design?

How can I leave test results (*.xml files) in work dir of console runner while having working dir for my tests set to bin/Debug?

notabug

Most helpful comment

@imakowski have you tried setting the current working directory to a known directory in an assembly setup? Untested code, but something like;

``` C#
[SetUpFixture]
public class MySetUpClass
{
[OneTimeSetUp]
RunBeforeAnyTests()
{
var dir = Path.GetDirectoryName(typeof(MySetUpClass).Assembly.Location);
Environment.CurrentDirectory = dir;

    // or
    Directory.SetCurrentDirectory(dir);
}

}
```

All 21 comments

This is by design, as shown here: https://github.com/nunit/nunit/wiki/Breaking-Changes

In earlier versions, NUnit changed the working directory. It no longer does so. You can use TestContext.TestDirectory to get the directory that contains the test assembly.

This breaks a lot of test! Why you changed that? Some of the tests cannot be fixed because runtime code of tested app had dependency that working directory is location of test assembly.

@imakowski have you tried setting the current working directory to a known directory in an assembly setup? Untested code, but something like;

``` C#
[SetUpFixture]
public class MySetUpClass
{
[OneTimeSetUp]
RunBeforeAnyTests()
{
var dir = Path.GetDirectoryName(typeof(MySetUpClass).Assembly.Location);
Environment.CurrentDirectory = dir;

    // or
    Directory.SetCurrentDirectory(dir);
}

}
```

@imakowski you may not have control over it, but code/applications should not rely on the current working directory being set. Applications should always determine their bin directory with code like I presented above. There are several API calls in Windows that change the current working directory without you being aware of it. Your application could run fine most of the time, but then fail after a user visits a seldom used part of of your application.

@rprouse this code is not working when is in the shadow copy mode
var dir = Path.GetDirectoryName(typeof(MySetUpClass).Assembly.Location);

You could use this in that case:
var dir = Path.GetDirectoryName(new Uri(typeof(MySetUpClass).Assembly.CodeBase).LocalPath);

Alternatively, we provide it for you as TestContext.CurrentContext.TestDirectory. :-)

We use the Uri as suggested with a few adjustments for special cases.

Alternatively, we provide it for you as TestContext.CurrentContext.TestDirectory. :-)

there is no TestDirectory property in CurrentContext anymore. i use nunit 3.6.1. there is only WorkDirectory which in my case when i start test from resharper points to wrong place :(

There is TestContext.TestDirectory. It is a static property. I believe that WorkDirectory is as well?

well, i can not find it either using visual studio browser or compiler or teleric decompiler.
but i see it in nunit 3.5. not sure what is wrong

I was wrong.

It is TestContext.CurrentContext.TestDirectory.

However, it is not there on the PORTABLE build.

#if !PORTABLE
        /// <summary>
        /// Gets the directory containing the current test assembly.
        /// </summary>
        public string TestDirectory
        {
            get
            {
                Assembly assembly = _testExecutionContext?.CurrentTest?.TypeInfo?.Assembly;

                if (assembly != null)
                    return AssemblyHelper.GetDirectoryName(assembly);

#if NETSTANDARD1_6
                // Test is null, we may be loading tests rather than executing.
                // Assume that the NUnit framework is in the same directory as the tests
                return AssemblyHelper.GetDirectoryName(typeof(TestContext).GetTypeInfo().Assembly);
#else
                // Test is null, we may be loading tests rather than executing.
                // Assume that calling assembly is the test assembly.
                return AssemblyHelper.GetDirectoryName(Assembly.GetCallingAssembly());
#endif
            }
        }
#endif

it is there in 3.6.0 but not in 3.6.1

I am looking at the current github repo, and it is exactly as I copied and pasted above.

Are you sure you are not using the PORTABLE build somehow?

yes, i'm using it

Well, that is why it is not there. It is not supported in the PORTABLE build, and never has been, to my knowledge. However, I have never used the PORTABLE build, just run the CI tests against it.

thank you

Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

For people eyeballing for actual code, putting together what @CharliePoole and @rprouse said, it's

[SetUpFixture]
public class MySetUpClass
{
    [OneTimeSetUp]
    public void RunBeforeAnyTests()
    {
        Environment.CurrentDirectory = TestContext.CurrentContext.TestDirectory;
        // or identically under the hoods
        Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory);
    }
}

For global initialization

Just don't enclose the above logic inside any namespace. i.e.

using NUnit.Framework;
using System;
using System.IO;

[SetUpFixture]
public class GlobalSetup
{
    [OneTimeSetUp]
    public void RunBeforeAnyTests()
    {
        Environment.CurrentDirectory = TestContext.CurrentContext.TestDirectory;
        // or identically under the hoods
        Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory);
    }
}

Also, seems the TestContext.CurrentContext.TestDirectory has some more intelligence to address corner cases, so I'd pick that over typeof(MySetUpClass).Assembly.Location

so I'd pick that over typeof(MySetUpClass).Assembly.Location

Location returns the shadow location if the assembly is shadow-copied, typically you wouldn't want that. Use CodeBase instead, which returns a Uri of the actual location it is initially run from, prior to any shadow-copying.

Obviously it is better to use TestDirectory, but there seem to be issues with that property, see #2872, causing exceptions that cannot be caught. I don't know if they can also appear if you use OneTimeSetup (I assume not), but care should be taken until that is addressed.

Was this page helpful?
0 / 5 - 0 ratings