AnonyMouse
AnonyMouse

Reputation: 18630

How to get Directory while running unit test

When running my unit test, I want to get the directory my project is running. Then I can retrieve a file.

Say I have a Test project named MyProject. Test I run:

AppDomain.CurrentDomain.SetupInformation.ApplicationBase

and I receive "C:\\Source\\MyProject.Test\\bin\\Debug".

This is close to what I'm after. I don't want the bin\\Debug part.

Anyone know how instead I could get "C:\\Source\\MyProject.Test\\"?

Upvotes: 106

Views: 135978

Answers (15)

Filippo Mondinelli
Filippo Mondinelli

Reputation: 11

This is my solution to get the location by recursion

internal static class PathUtil
{
    internal static string GetRoot()
    {
        var binFolder = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
        var assemblyName = Assembly.GetCallingAssembly().GetName().Name;
        return Reduce(binFolder, assemblyName!)};
    }

    private static string Reduce(string? path, string lastFolder) => path switch
    {
        not null when path.EndsWith(lastFolder) => path,
        not null when path == string.Empty => ".\\",
        not null => Reduce(Path.GetDirectoryName(path), lastFolder),
        _ => ".\\"
    };
}

Upvotes: 0

Louis Go
Louis Go

Reputation: 2588

According to https://github.com/nunit/nunit/issues/742#issuecomment-121964506

For NUnit3 , System.Environment.CurrentDirector is never changed, so it shall be the path of solution.

Eg:

string szProjectPath = System.Environment.CurrentDirectory + @"\where\your\project\is";

I prefer fixed location rather than GetParent(). One drawback of GetParent is when build is changed from AnyCPU to x86, default path would be changed from bin\Debug to bin\x86\Debug. Need to get another parent, and it's pain in the neck.

Also, you may still access to you test assemblies at TestContext.CurrentContext.TestDirectory and get output from TestContext.CurrentContext.WorkDirectory

Edit: Note: There are many changes in NUnit3. I will suggest reading through the documentation about "Breaking changes"

Upvotes: 4

zls
zls

Reputation: 1

use StackTrace

    internal static class Extensions
    {
        public static string GetSourceDirectoryName(this Type type)
        {
            StackTrace stackTrace = new StackTrace(true);

            foreach (var frame in stackTrace.GetFrames())
            {
                if (frame.GetMethod() is { } method && method.DeclaringType == type)
                {
                    return Path.GetDirectoryName(frame.GetFileName());
                }
            }

            throw new Exception($"未找到{type.Name}源文件目录");
        }
    }

Upvotes: 0

Ilian
Ilian

Reputation: 5355

I would do it differently.

I suggest making that file part of the solution/project. Then right-click -> Properties -> Copy To Output = Copy Always.

That file will then be copied to whatever your output directory is (e.g. C:\Source\MyProject.Test\bin\Debug).

Edit: Copy To Output = Copy if Newer is the better option

Upvotes: 92

Darien Pardinas
Darien Pardinas

Reputation: 6186

Usually you retrieve your solution directory (or project directory, depending on your solution structure) like this:

string solution_dir = Path.GetDirectoryName( Path.GetDirectoryName(
    TestContext.CurrentContext.TestDirectory ) );

This will give you the parent directory of the "TestResults" folder created by testing projects.

Upvotes: 57

Sau001
Sau001

Reputation: 1664

My approach relies on getting the location of the unit testing assembly and then traversing upwards. In the following snippet the variable folderProjectLevel will give you the path to the Unit test project.

string pathAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
string folderAssembly = System.IO.Path.GetDirectoryName(pathAssembly);
if (folderAssembly.EndsWith("\\") == false) {
    folderAssembly = folderAssembly + "\\";
}
string folderProjectLevel = System.IO.Path.GetFullPath(folderAssembly + "..\\..\\");

Upvotes: 1

Jeremy Thompson
Jeremy Thompson

Reputation: 65554

Further to @abhilash's comment.

This works in my EXE's, DLL's and when tested from a different UnitTest project in both Debug or Release modes:

var dirName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.Replace("bin\\Debug", string.Empty));

Upvotes: 12

Ogglas
Ogglas

Reputation: 69968

You can do it like this:

using System.IO;

Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, @"..\..\"));

Upvotes: 0

houss
houss

Reputation: 710

In general you may use this, regardless if running a test or console app or web app:

// returns the absolute path of assembly, file://C:/.../MyAssembly.dll
var codeBase = Assembly.GetExecutingAssembly().CodeBase;    
// returns the absolute path of assembly, i.e: C:\...\MyAssembly.dll
var location = Assembly.GetExecutingAssembly().Location;

If you are running NUnit, then:

// return the absolute path of directory, i.e. C:\...\
var testDirectory = TestContext.CurrentContext.TestDirectory;

Upvotes: 1

noelicus
noelicus

Reputation: 15055

For NUnit this is what I do:

// Get the executing directory of the tests 
string dir = NUnit.Framework.TestContext.CurrentContext.TestDirectory;

// Infer the project directory from there...2 levels up (depending on project type - for asp.net omit the latter Parent for a single level up)
dir = System.IO.Directory.GetParent(dir).Parent.FullName;

If required you can from there navigate back down to other directories if required:

dir = Path.Combine(dir, "MySubDir");

Upvotes: 4

user1207577
user1207577

Reputation: 699

/// <summary>
/// Testing various directory sources in a Unit Test project
/// </summary>
/// <remarks>
/// I want to mimic the web app's App_Data folder in a Unit Test project:
/// A) Using Copy to Output Directory on each data file
/// D) Without having to set Copy to Output Directory on each data file
/// </remarks>
[TestMethod]
public void UT_PathsExist()
{
    // Gets bin\Release or bin\Debug depending on mode
    string baseA = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    Console.WriteLine(string.Format("Dir A:{0}", baseA));
    Assert.IsTrue(System.IO.Directory.Exists(baseA));

    // Gets bin\Release or bin\Debug depending on mode
    string baseB = AppDomain.CurrentDomain.BaseDirectory;
    Console.WriteLine(string.Format("Dir B:{0}", baseB));
    Assert.IsTrue(System.IO.Directory.Exists(baseB));

    // Returns empty string (or exception if you use .ToString()
    string baseC = (string)AppDomain.CurrentDomain.GetData("DataDirectory");
    Console.WriteLine(string.Format("Dir C:{0}", baseC));
    Assert.IsFalse(System.IO.Directory.Exists(baseC));


    // Move up two levels
    string baseD = System.IO.Directory.GetParent(baseA).Parent.FullName;
    Console.WriteLine(string.Format("Dir D:{0}", baseD));
    Assert.IsTrue(System.IO.Directory.Exists(baseD));


    // You need to set the Copy to Output Directory on each data file
    var appPathA = System.IO.Path.Combine(baseA, "App_Data");
    Console.WriteLine(string.Format("Dir A/App_Data:{0}", appPathA));
    // C:/solution/UnitTestProject/bin/Debug/App_Data
    Assert.IsTrue(System.IO.Directory.Exists(appPathA));

    // You can work with data files in the project directory's App_Data folder (or any other test data folder) 
    var appPathD = System.IO.Path.Combine(baseD, "App_Data");
    Console.WriteLine(string.Format("Dir D/App_Data:{0}", appPathD));
    // C:/solution/UnitTestProject/App_Data
    Assert.IsTrue(System.IO.Directory.Exists(appPathD));
}

Upvotes: 9

The best solution I found was to put the file as an embedded resource on the test project and get it from my unit test. With this solution I don´t need to care about file paths.

Upvotes: 2

manu_dilip_shah
manu_dilip_shah

Reputation: 900

Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;

This will give you the directory you need....

as

AppDomain.CurrentDomain.SetupInformation.ApplicationBase 

gives nothing but

Directory.GetCurrentDirectory().

Have alook at this link

http://msdn.microsoft.com/en-us/library/system.appdomain.currentdomain.aspx

Upvotes: 38

AHM
AHM

Reputation: 5225

I normally do it like that, and then I just add "..\..\" to the path to get up to the directory I want.

So what you could do is this:

var path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"..\..\";

Upvotes: 6

David Z.
David Z.

Reputation: 5701

I'm not sure if this helps, but this looks to be briefly touched on in the following question.

Visual Studio Solution Path environment variable

Upvotes: 1

Related Questions