C# 等待单元测试中引发的异步事件

C# 等待单元测试中引发的异步事件,c#,unit-testing,events,asynchronous,C#,Unit Testing,Events,Asynchronous,我正试图通过单元测试对事件SmtpClient.send的引发进行单元测试,但我遇到了一个恼人的问题,即在事件实际触发之前,测试仍在继续进行,在没有实际到达事件之前终止应用程序。因此,想象一下下面的代码: [TestClass] public class emailTest { public bool sentEmail = false; [TestMethod] public void sendEmail() { SmtpClient smtp

我正试图通过单元测试对事件SmtpClient.send的引发进行单元测试,但我遇到了一个恼人的问题,即在事件实际触发之前,测试仍在继续进行,在没有实际到达事件之前终止应用程序。因此,想象一下下面的代码:

[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);
    }
}
然后测试通过了

让该方法通过将其包装为任务来等待smtp.SendAsync实际上似乎不起作用,因为我实际上没有等待SendAsync,我正在尝试等待SendCompleted完成执行,然后再继续进行其余的测试,我不太确定如何做

由于时间原因,我只需等待SendCompleted完成处理的最短时间,这一点非常重要

我做了大量的搜索,但似乎找不到任何解决这个具体问题的方法


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

好吧,我必须承认,
SendCompleted
只有在
SendAsync
返回后才会触发这一事实听起来有点奇怪。。。它确实使单元测试变得更加困难

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

// 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);

您测试
SmtpClient
有什么原因吗?这不是您编写的代码,所以测试它有什么意义?我不是在测试SmtpClient,我知道它可以工作。我正在自定义处理程序中测试代码。您应该在测试中模拟
SmtpClient
,这样您的测试就不会依赖于
SmtpClient
的行为。如中的示例。创建SmtpClient的传真如何帮助我确定实际SmtpClient中事件的时间?我不是在测试事件是否触发,或者SmtpClient是否真的做了任何事情。我正在测试事件触发的时间。若我无法在事件触发时牢牢锁定,那个么我将不得不继续插入一个次优的手动延迟。您的测试不应该在SmtpClient的实际计时上。您无法控制这一点-这是框架的一个实现细节。在您的控制之外测试代码是没有用的。使用模拟SmtpClient,您可以控制计时(例如,立即触发SendCompleted事件),这样您就可以确保SendComplete处理程序立即运行。我刚刚尝试了这个方法,但没有成功,但我只是把50秒的延迟放回断言之前,如果我检查布尔值,测试通过,但如果我检查wasSignaled,则测试不通过。i、 e.smtp.SendCompleted+=(s,e)=>{are.Set();sentEmail=true;}@用户3657661“它不工作”是什么意思。这对推动对话没有任何作用。这个问题已经被回答了两次:在这个答案中(有效)和在我申请的副本中。我所说的“它不起作用”显然是指测试失败。这个答案显然行不通,我可以证明这一点。注意这个链接:如果你要声称代码客观地工作,而人们却声称它不工作,那么你至少可以亲自测试它,它只有几行。这段代码中设置为1秒的超时时间可能太短了。如果你花时间去理解它在做什么,你可以把超时时间改为无穷大。;你也没有回复副本。