0

我正在编写一个期望从它正在调用的对象接收事件的测试。具体来说,我正在调用一个通过 SSH(使用开源 Granados 项目)连接到 AIX 机器的对象,然后断开连接,并且我想确保收到在断开连接期间引发的 OnConnectionClosed 事件。这听起来很简单,过去我写过很多这样的测试,但是这次发生了一些我认为与线程有关的奇怪行为。

基本上,我调用的对象是在与我调用它的线程不同的线程上引发“OnConnectionClosed”事件。我看到的是,当我通过从 UI 中选择“调试测试”来运行测试时,它通过了,但是如果我选择“运行测试”,它就会失败(即使在调试运行期间没有设置断点)。我做了一些谷歌搜索,发现这篇文章似乎表明默认情况下 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;
    }
}
4

2 回答 2

2

使用 System.Threading 命名空间中的 WaitHandle 类。AutoResetEvent 或 ManualResetEvent。两者的区别在于 AutoResetEvent 每次设置时让一个线程继续执行,而 ManualResetEvent 则在设置时释放所有等待线程。

您的示例不起作用的原因与编译器优化有关。代码实际上并没有按照您乍一看的想法进行编译。最有可能的是,编译器会做一些事情,比如将局部变量放在寄存器中,并且在检查循环期间从不实际获取它。您可以使用 volatile 关键字来避免这种类型的事情,但我强烈建议您阅读有关线程和并发的更多详细信息。Joe Duffy 的博客http://www.bluebytesoftware.com是一个很好的入门资源,我强烈推荐他即将出版的《Windows 上的并发编程》一书。

于 2008-10-20T21:09:18.603 回答
0

不完全是您所问的,但您可以通过查看名为CHESS的 MS 研究项目找到一些可行的解决方案或至少想法。它用于 .net 中的多线程并发测试。

于 2008-10-20T21:46:18.653 回答