我正在编写一个测试,希望从正在调用的对象接收事件。具体来说,我正在调用一个通过SSH连接到AIX机器的对象(使用开源Granados项目),然后断开连接,我想确保收到断开连接期间引发的OnConnectionClosed事件。这听起来很简单,我过去曾写过很多像这样的测试,但这次发生了一些我认为与线程有关的奇怪行为。
基本上,我调用的对象是在与我调用它不同的线程上引发'OnConnectionClosed'事件。我所看到的是,当我通过从UI中选择“调试测试”来运行测试时,它会通过,但是如果我选择“运行测试”,它就会失败(即使在调试运行期间没有设置断点)。我做了一些谷歌搜索,发现this post似乎表明默认情况下MSTest主机以单线程模式运行,但配置更改可以使其在多线程模式下运行。这听起来像是逻辑上解决我的问题,但当然,它没有。
我遇到的其他一些帖子也让我觉得MSTest根本就没有监视后台线程(所以他们提出的事件没有被“听到”)。这也是有道理的,因为它似乎在调试模式下工作,似乎上面的修复应该在逻辑上解决这个问题,然后我很困惑为什么它不起作用。有可能我只是没有正确处理线程,尽管如果是这样的话,我希望在调试模式下仍然存在问题。
还有其他人试图以类似的方式测试某些东西吗?如果是这样,你遇到过类似的问题吗?如果是这样,你是如何解决它们的?
我已粘贴下面的相关单元测试代码(出于安全原因,我已删除了连接信息)。
[TestClass]
public class SSHReaderTests
{
private bool received = false;
private delegate bool SimpleFunc();
[TestInitialize]
public void MyTestInitialize()
{
received = false;
}
[TestMethod]
public void Should_raise_OnReaderConnectionClosed_event_after_successful_connection_is_disconnected()
{
IReader reader = new SSHReader();
reader.OnReaderConnectionClosed += delegate
{
received = true;
};
reader.Connect("*****", "*****", "*****");
//Assert.IsTrue(reader.IsConnected);
reader.Disconnect();
//Assert.IsFalse(reader.IsConnected);
Assert.IsTrue(WaitUntilTrue(delegate {
return received; }, 30000, 1000));
}
private static bool WaitUntilTrue(SimpleFunc func, int timeoutInMillis, int timeBetweenChecksInMillis)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while(stopwatch.ElapsedMilliseconds < timeoutInMillis)
{
if (func())
return true;
Thread.Sleep(timeBetweenChecksInMillis);
}
return false;
}
}
答案 0 :(得分:2)
使用System.Threading命名空间中的WaitHandle类。 AutoResetEvent或ManualResetEvent。两者之间的区别在于AutoResetEvent允许每次设置一个线程,而ManualResetEvent释放set上的所有等待线程。
您的示例不起作用的原因与编译器优化有关。代码实际上并没有编译成你初看起来的想法。最有可能的是,编译器会执行类似的操作,例如将局部变量放在寄存器中,并且在检查的循环期间从不实际获取它。您可以使用volatile关键字来避免这种类型的事情,但我强烈建议您阅读线程和并发性以获取更多详细信息。 Joe Duffy在http://www.bluebytesoftware.com的博客是一个很好的入门资源,我强烈推荐他即将发布的Windows并发编程书。
答案 1 :(得分:0)
不完全是您所询问的内容,但您可以通过查看名为CHESS的MS Research项目找到一些可行的解决方案或至少一些想法。它适用于.net中的多线程并发测试。