运行单元测试时如何获取目录

嗨,当运行我的单元测试时,我想要得到我的项目正在运行的目录来检索一个文件。

假设我有一个名为 MyProject 的测试项目:

AppDomain.CurrentDomain.SetupInformation.ApplicationBase

我收到 "C:\\Source\\MyProject.Test\\bin\\Debug"

这和我要找的东西很接近,我不想要 bin\\Debug那部分。

有人知道我怎样才能得到 "C:\\Source\\MyProject.Test\\"吗?

112470 次浏览

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

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 + @"..\..\";

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

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

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.

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.

/// <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));
}

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");

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;

You can do it like this:

using System.IO;


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

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));

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 + "..\\..\\");

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"

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}源文件目录");
}
}