【问题标题】:multithreaded unit test - notify calling thread of event to stop sleeping多线程单元测试 - 通知事件的调用线程停止睡眠
【发布时间】:2014-10-21 03:35:42
【问题描述】:

我编写了一个测试 (NUnit) 来测试我的 Amazon SES 电子邮件发送功能,该功能应该在我的 Amazon SQS 队列中生成退回通知。我在一个新线程上循环轮询该队列 1 分钟,以等待并验证退回通知。

我想将时间增加到几分钟,以确保我不会错过它。但是响应可能会在几秒钟内出现,在这种情况下,我只想记录花费多长时间并完成测试,因为一旦验证收据,就没有必要继续等待了。

我怎样才能以干净的方式完成这个线程场景,我的意思是不污染 MethodInMainApp() 与测试代码。在主应用程序中,这不应该发生(它应该无限期地继续轮询),它应该只在测试早期停止。我可能应该从两个入口点传入 ThreadStart 函数,但这并不能回答我问的问题。

   [Test]
    public async void SendAndLogBounceEmailNotification() 
    {

        Thread bouncesThread = Startup.MethodInMainApp();
        bouncesThread.Start();

        bool success = await _emailService.SendAsync(...);

        Assert.AreEqual(success, true);

        //Sleep this thread for 1 minute while the 
        //bouncesThread polls for bounce notifications
        Thread.Sleep(60000); 
    }


   public static Thread MethodInMainApp()
    {
        ...


        Thread bouncesThread = new Thread(() =>
        {
            while (true)
            {
                ReceiveMessageResponse receiveMessageResponse = sqsBouncesClient.ReceiveMessage(bouncesQueueRequest);
                if(receiveMessageResponse.Messages.Count > 0) 
                { 
                     ProcessQueuedBounce(receiveMessageResponse);
                     //done for test
                }                    
            }
        });

        bouncesThread.SetApartmentState(ApartmentState.STA);
        return bouncesThread;
    }

【问题讨论】:

    标签: c# multithreading unit-testing nunit


    【解决方案1】:

    使用 Monitor 类。

    用这个代替Thread.Sleep(60000)

    lock (_lockObject)
    {
        Monitor.Wait(_lockObject, 60000);
    }
    

    然后你想在哪里发信号让线程继续:

    lock (_lockObject)
    {
        Monitor.Pulse(_lockObject);
    }
    

    当然,这需要在类的某处添加static readonly object _lockObject = new object()

    我并不是说总体策略实际上是正确的方法。似乎在这里,单元测试方法最好显式调用一些其他方法来等待和验证响应。但以上内容应该解决您的具体问题。

    【讨论】:

    • 嘿,谢谢,但我收到错误“对象同步方法是从未同步的代码块调用的”。我在测试类上创建了 lockobject 并将其作为可选参数传递到我的方法中。这样我可以在它不是测试时忽略它,只做 if(lockobject != null) Monitor.Pulse(lockobject);该行抛出错误
    • 正如错误消息所说,您在调用 Monitor.Pulse() 时没有先锁定对象。如果你想让它成为可选的,很好。但是在允许调用 Monitor.Pulse() 之前,您仍然需要“lock (lockobject)”。
    猜你喜欢
    • 2015-06-28
    • 1970-01-01
    • 2019-05-24
    • 2011-05-14
    • 2019-11-29
    • 2011-11-10
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    相关资源
    最近更新 更多