【问题标题】:Wait for an asyncrhonous event raised event in a unit test [duplicate]在单元测试中等待异步事件引发事件[重复]
【发布时间】:2015-08-26 18:50:53
【问题描述】:

我正在尝试对从单元测试中引发的事件 SmtpClient.SendCompleted 进行单元测试,我遇到了一个烦人的问题,即在事件实际触发之前继续处理测试,终止应用程序而不实际到达事件。所以,想象一下下面的代码:

[TestClass]
public class emailTest
{
    public bool sentEmail = false;

    [TestMethod]
    public void sendEmail()
    {
        SmtpClient smtp = new SmtpClient("smtpserver");
        smtp.SendCompleted += delegate(Object sender, System.ComponentModel.AsyncCompletedEventArgs e) { sentEmail = true; };
        MailMessage mm = new MailMessage("from@address.com", "to@address.com", "test subject", "test body");
        smtp.SendAsync(mm, "test");
        Assert.IsTrue(sentEmail);
    }
}

但是,如果我像这样手动插入延迟,则此测试失败...

[TestClass]
public class emailTest
{
    public bool sentEmail = false;

    [TestMethod]
    public void sendEmail()
    {
        SmtpClient smtp = new SmtpClient("smtpserver");
        smtp.SendCompleted += delegate(Object sender, System.ComponentModel.AsyncCompletedEventArgs e) { sentEmail = true; };
        MailMessage mm = new MailMessage("from@address.com", "to@address.com", "test subject", "test body");
        smtp.SendAsync(mm, "test");
        System.Threading.Thread.Sleep(50000); // Manual Delay
        Assert.IsTrue(sentEmail);
    }
}

那么测试通过了。

通过将方法 await smtp.SendAsync 包装为任务似乎并没有真正起作用,因为我实际上并没有等待 SendAsync,我正在尝试等待 SendCompleted 完成执行,然后再继续其余部分测试,我不太确定该怎么做。

出于时间原因,我只等待最少的时间让 SendCompleted 完成处理是非常重要的。

我进行了大量搜索,但似乎找不到任何解决此特定问题的内容。

快速编辑:在所有情况下,电子邮件都成功发送,只有测试失败。

【问题讨论】:

  • 你测试SmtpClient有什么原因吗?这不是您编写的代码,那么测试它的意义何在?
  • 我不是在测试 SmtpClient,我知道它可以工作。我正在自定义处理程序中测试代码。
  • 您应该只在测试中模拟 SmtpClient,这样您的测试就不会依赖于 SmtpClient 的行为。就像stackoverflow.com/questions/19971364/…中的例子一样。
  • 创建 SmtpClient 的传真如何帮助我确定实际 SmtpClient 中的事件时间?我不是在测试事件是否触发,或者 SmtpClient 是否真的做任何事情。我正在测试事件触发的时间。如果在事件触发时我无法牢固锁定,那么我将不得不继续插入一个次优的手动延迟。
  • 您的测试不应该在 SmtpClient 的实际时间上进行。你无法控制它——它是框架的一个实现细节。在您的控制之外测试代码没有用。使用模拟 SmtpClient,您可以控制时间(例如立即触发 SendCompleted 事件),因此您可以确保您的 SendComplete 处理程序立即运行。

标签: c# unit-testing events asynchronous


【解决方案1】:

好吧,我必须承认 SendCompleted 仅在 SendAsync 返回后才被触发的事实听起来有点奇怪......它确实使单元测试更加困难。

但是,如果您想等待最少的时间,则必须引入同步原语。 AutoResetEvent 听起来很适合这种情况。

// Arrange
var are = new AutoResetEvent(false);

var smtp = new SmtpClient("smtpserver");
smtp.SendCompleted += (s, e) => { are.Set(); };
var mm = new MailMessage("from@address.com", "to@address.com", "test subject", "test body");

// Act
smtp.SendAsync(mm, "test");

// Assert
var wasSignaled = are.WaitOne(timeout: TimeSpan.FromSeconds(1));
Assert.True(wasSignaled);

【讨论】:

  • 我刚刚尝试过,但没有成功,但我只是在断言之前将 50 秒延迟放回原处,如果我检查了布尔值,则测试通过,但如果我检查了 wasSignaled,则测试通过。即 smtp.SendCompleted += (s, e) => {are.Set();已发送电子邮件 = 真; };
  • @user3657661 “它不起作用”是什么意思。这无助于推进对话。这个问题已经回答了两次:在这个答案(有效)和我申请的副本中。
  • “它不起作用”显然是指测试失败。这个答案显然行不通,我可以证明。观察这个链接:imgur.com/a/XtzVg如果你要声称代码客观地工作而人们声称它不工作,你至少可以自己测试一下,它只有几行。
  • 可能这段代码中设置为 1 秒的超时时间太短了。如果您花时间了解它在做什么,您可以将超时更改为无穷大。您也没有回复重复的内容。
猜你喜欢
  • 2010-12-26
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
  • 2018-12-27
  • 2011-10-04
  • 1970-01-01
  • 2019-03-21
  • 1970-01-01
相关资源
最近更新 更多