使用Resharper进行单元测试中的路径问题
前言
Resharper是C#开发中一个功能非常强大的插件,其提供的UnitTestRunner
在进行单元测试时使用起来非常方便。正是因为其功能过于强大,很多的配置项我们不清楚其功能,在使用时会遇到一些匪夷所思的问题而招不到问题的根源。本文将要解释和解决的就是TestRunner
中的路径问题。
问题背景
博主在最近的一个项目中需要使用C++/CLI对C++的DLL进行封装,封装后生成一个新的DLL供C#应用程序调用。CLI的包装类中通过相对路径的形式指定了C++的DLL的存放路径,并用如下代码进行了DLL的导入:
FARPROC clr_adapter::invoke_method(const LPCSTR name)
{
LPCWSTR dll_path = L".\\libcobra.dll";
HMODULE handle = GetModuleHandle(dll_path);
if (handle == nullptr)
handle = LoadLibrary(dll_path);
if (handle == nullptr)
return nullptr;
return GetProcAddress(handle, name);
}
上述代码可以看出,我是想导入\Debug\libcobra.dll。直接启动C#程序,调用正常。但是在C#的单元测试程序中却招不到该dll,LoadLibrary
函数抛出126异常(调用GetErrorCode()
可知)。
问题分析
WINAPI中126异常对应的是找不到DLL或者其依赖项。鉴于我所有的依赖DLL都放在了Debug目录下,所以肯定不是依赖项找不到的问题。所以我写了如下代码查看当前的工作目录:
Debug.WriteLine(Environment.CurrentDirectory);
结果如下:
C:\Users\\*\AppData\Local\JetBrains\Installations\ReSharperPlatformVs15_80ff4cd5
至此,问题已非常明显,Resharper创建了一个临时目录启动单元测试,但是却没有把相关的依赖项如DLL、配置文件或数据文件等拷贝过去。
问题解决
通过谷歌resharper test runner current directory
关键字,在Stack Overflow中找到了同病相怜的朋友,而各路大神也给出了问题分析及解决方案:
-
关闭Resharper的shadow-copy功能
NUnit 3.0 stopped changing current directory. It’s a bad idea for us to do that anyway and it’s a really bad idea with 3.0, when multiple assemblies in differing directories may be running at the same time.
因为上述原因,方法1并不好使,但是我并没有测试NUnit 2.x的版本,所以不好说对NUnit 2.x版本是否有效。
-
代码中涉及到相对路径的地方使用:
AppDomain.CurrentDomain.BaseDirectory;
如果所有代码都是自己写的,这么做的确能解决问题。但有些时候我们需要调用别人的DLL,没办法要求别人也这么写,而且有可能也做不到。
-
终极方案:执行单元测试时改变当前目录
[SetUp]
public void SetDirectory()
{
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
}
[Test]
public void ShowDirectory_AlwaysTrue()
{
Debug.WriteLine(Environment.CurrentDirectory);
Assert.True(true);
}
这时候再运行单元测试,发现结果已变为:
D:\work_space\GUI\trafficDemo\CalculateFormula\Bin_Debug
至此,问题彻底解决!