Visual Studio 2012测试资源管理器锁定原生 .dll,导致重建失败。

24

我正在使用Visual Studio 2012来处理一个包含C#和C++/CLI .dll的解决方案,其中C++/CLI .dll引用原生的.dll库(比如boost库)。C++代码被编译为x64。

当我打开VS时,我可以清理并构建我的项目。

使用测试资源管理器,我可以运行我的测试。

但是,一旦我使用测试资源管理器运行测试一次之后,我就无法重新构建项目。似乎VS2012测试资源管理器会锁住我的C++/CLI-dll,导致出现以下错误:

LNK1104: cannot open file 'C:\Dev\LockExample\bin\Debug\cli.dll'
由此产生的问题是,每当我使用Test Explorer运行测试时,都需要重新启动VS2012才能继续开发。很明显,这不是可持续的开发过程。
使用仅包含C#的dll进行测试和重建没有问题——据我所知,该问题仅出现在使用本机x64代码的DLL中。
经过进一步测试,我发现罪魁祸首是vstest.executionengine.exe。使用SysInternals中的handle命令,我发现vstest.executionengine.exe会锁定cli-dll的.dll和.pdb文件。它不会锁定仅管理的dll。
如何让Visual Studio Test Explorer在测试运行完成后释放C++/Cli dll上的锁?

在 VS 2017 中发现了同样的问题,涉及到引用的非托管 DLL。 - Slobodan Savkovic
6个回答

30
在 Visual Studio 2013 中,这个问题可以通过在菜单中选择“测试 -> 测试设置”并取消选中“保持测试执行引擎运行”选项来轻松解决。
我在另一篇帖子中找到了答案: vstest.executionengine.x86.exe not closing

9

经过进一步搜索,我找到了connect.microsoft.com上的这篇文章。其中workarounds中的最后一个提示确实解决了问题,但它只是一个不太好看的hack。

如果我将以下内容添加为C++/CLI dll的预构建事件,就可以进行重新构建:

taskkill /F /IM vstest.executionengine.exe /FI "MEMUSAGE gt 1"
taskkill /F /IM vstest.executionengine.x86.exe /FI "MEMUSAGE gt 1"

这将终止vstest.executionengine.exe进程,从而释放对我的.dll文件的锁定。

1
这个“解决方案”对我来说可行,尽管它很丑陋。我只是会尽量不去看它... - rom99

3
我在测试中遇到了涉及本地dll的问题。我找到的解决方法是在测试中添加DeploymentItemAttribute - 不确定这是否普遍适用,但对我来说肯定有效。如果有很多这样的dll文件,这可能会有点麻烦(我的情况下有6个),但一旦完成,就可以轻松地复制和粘贴到其他测试中。
因此,我的单元测试类看起来像这样:
[TestClass]
public class TestMyClass
{
    [TestMethod]
    [DeploymentItem("firstnative.dll")]
    [DeploymentItem("secondnative.dll")]
    public void TestMyMethod()
    {
        //Code which (indirectly) uses the above native dlls.
    }
}

2

我曾经也遇到过这个问题,并使用了“taskkill”解决方法,但是我刚刚在VS2013设置中发现了一个更优雅的解决方法:

取消选中

在测试运行之间保持测试执行引擎运行

选项,该选项位于

工具/选项/ Web性能测试工具


对我来说不起作用,但我没有构建Web项目 - 我猜这个选项只适用于Web项目?也许有其他地方的选项我找不到。 - rom99
这只解决了在使用“测试资源管理器”时的问题。我正在对C#应用程序进行单元测试(与任何Web相关的东西都不相关!),这解决了我的问题。你是否在使用“测试执行引擎”?如果没有,那么可能是另一个进程锁定了“bin”中的任何二进制输出文件。 - axeloide
是的,我正在使用测试执行引擎,似乎在测试运行后对某些二进制文件(sqlite dlls)保持锁定状态。当我使用命令行工具vstest.console.exe运行相同的测试时,一切都按预期工作,并且二进制文件没有被锁定。顺便说一句,使用命令行工具运行测试也要快得多(或者可能不是测试本身,而是测试运行器更快)。但我偏离了主题... - rom99

1
我曾编写了一个C#实用程序,用于加载和卸载本机库,在这里。我在测试项目中使用了它,如下所示。由于它在Dispose中卸载dll,所以我不会出现构建错误。
public interface INativeCrypto : INativeImport
{
    [ImportFunction("mynative.dll"]
    int NativeMethod();
}


[TestClass]
public class UnitTest1
{
    public void TestMethod1()
    {
        INativeCrypto impl = NativeImport.Create<INativeCrypto>("");

        // Use methods in impl
        int i = impl.NativeMethod();
        //...
    }
}

1

在@frodesto的回答中添加一些内容(如果是VS2013),“Test> Test Setting> Keep Test Executing Engine running”配置存储在用户配置(SUO文件)中。如果此错误发生在TFS Build代理中,这可能有点麻烦,因为它使用服务默认用户。

要解决此问题,请首先终止现有的vstest.executionengine.exe,将TFS Build代理使用的用户修改为您登录的用户。打开存储在TFS Build代理工作区中的解决方案并取消选择该选项。之后,TFS Build代理将读取“保持测试执行引擎”选项,因为SUO文件是针对同一用户的。


此选项仅适用于新版本的VS。 - Wilbert
我知道,我只是在为VS2013(我指出了frodesto答案中非常明显的地方)和TFS添加一些提示。但可能我没有表达清楚,我会编辑我的回答。 - Jon Ander Ortiz Durántez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接