【发布时间】:2016-10-09 11:48:10
【问题描述】:
我有一个非托管的DLL,我正在尝试为其创建一个.NET 包装库,但是当我尝试对其运行NUnit(v3) 测试时,与它只是从按钮单击一个 WinForm 应用程序。
背景:在 DLL 启动期间,我调用了它的Connect() 方法,最终导致 DLL 建立 TCP 连接。当 TCP 连接建立后,我会通过将处理程序连接到其“已连接”事件来获得通知。
连接后,我会在 DLL 上调用其他命令。
在一个简单的测试 Winforms 应用程序中,我有 1 个按钮来实例化“DLL”,然后调用 Connect() 方法。当线程完成时,应用程序会闲置大约 2 秒,然后“已连接”事件处理程序按预期触发。该事件不返回任何内容。
但是因为connect() 是一项昂贵的操作,而且因为我的库注定要用于更大的应用程序,所以我在我的库中创建了一个ConnectAsync() 方法并使用了async and await 关键字和AutoResetEvent . ConnectAsync() 方法在收到通知 TCP 连接已从事件启动后返回“实例化”DLL 的实例。
对测试 WinForms 应用程序进行了一些重构,它按预期工作。
下一步是使用 NUnit 进行集成测试。但是,当从异步测试调用 ConnectAsync() 方法时,我可以看到远程应用程序上建立了 TCP 连接,但事件处理程序永远不会触发。一天的测试、搜索和反复试验无法解释为什么 ConnectAsync() 在简单的 Winforms 按钮上完美运行,但在 UnitTest 中却不行。
这是测试代码
[Test()]
public async Task Test1()
{
var conn = await GetConnection();
//assert some commands on the conn
}
private async Task<TCPConnector> GetConnection()
{
return await Task.Run(() =>
{
var mre = new AutoResetEvent(false);
var ctrl = new TCPConnector();
ctrl.serverName = server;
ctrl.serverPort = serverPort;
ctrl.onConnected += () => { mre.Set(); };
ctrl.Connect();
mre.WaitOne();
return ctrl;
});
}
我知道这不是一个严格的问题,但我很困惑,正在寻找尝试的想法。或者是关于按钮单击事件和 NUnit 测试执行之间有什么不同的指针。
如果它对某人意味着什么,我调用的 dll 是一个非托管的 ActveX
更新1: 如果使用 MSTest 它可以工作!所以跟NUnit的启动环境有关。
更新 2: 通过this SO 帖子中的调查,我偶然在没有任何单元测试框架的情况下复制了相同的行为,而是通过 reg free COM。所以我现在认为这与 COM 的激活和消耗方式有关?
分辨率
终于找到了答案。
感谢 Chris 对this 问题的回答。我所要做的就是按照概述在清单中添加一个<comInterfaceExternalProxyStub /> 部分,然后宾果游戏
更新 4
忽略最近的更新和解决方案。它们包含误导和误报,以及当我在整个 COM、Regfree COM、Interop 和 COM 事件的世界中工作时代表我缺乏理解。问题仍未解决。
关键问题仍然是,当 COM 在单元测试的上下文中运行时,COM 事件不会触发。在普通的 .exe 中运行时,它们工作得很好
【问题讨论】:
-
提供更多关于测试代码的细节
-
@OrdinaryOrange:我会尝试 using
TaskCompletionSource而不是Task.Run和AutoResetEvent。 -
感谢斯蒂芬的建议。我按照建议重构了代码以使用
TaskCompletionSource,但得到的结果与以前相同。我想这一定是启动环境之间的一些差异。
标签: c# .net winforms nunit unmanaged