发送电子邮件并创建新线程的单元测试

发布于 2024-12-04 07:04:41 字数 1156 浏览 0 评论 0原文

我真的感觉很糟糕。

我有一个发送电子邮件以获取通知的 Web 应用程序。

它是一个包含发送电子邮件的基本方法的类,如下所示:

 MailMessage email = new MailMessage();

        email.To.Add("[email protected]");

        email.Subject = "Test";
        email.Body = "t";

        SmtpClient client = new SmtpClient();

        client.Send(email);

但我有一个名为 NotificatorService 的服务来验证某些逻辑,并且因为这只是一个“额外”,所以在新线程中调用该服务的方法。我所做的是:

public void NotifyMembers(NotificatorClientDTO clientDto) {
if(clientDto == null)
    throw new ArgumentNullException("clientDto");


Thread t = new Thread( 
    () => {
    // go to database, verify business rules, etc...

    // At the end if it is ok, invoke the method that sends a email
}

t.Start()

}

如果我创建一个实例化 NotificatorService 的单元测试并使用一些数据调用 notificationMembers,则代码将引发异常,但前提是我在单独的线程中执行。

我创建的线程设置在前台,因此系统不会破坏我认为的进程。

异常消息是这样的:

SmtpException:无法评估表达式,因为代码已优化或本机框架位于调用堆栈的顶部

我走到 2 个内部异常,并看到此

_消息“线程正在中止”。字符串

为什么会发生这种情况? 什么原因导致线程中止?

I really am feeling bad.

I have one web application that sends Emails for notifications.

It is a class that contains a basic method that sends a email like this:

 MailMessage email = new MailMessage();

        email.To.Add("[email protected]");

        email.Subject = "Test";
        email.Body = "t";

        SmtpClient client = new SmtpClient();

        client.Send(email);

But i have a service called NotificatorService that verify some logic, and because this is just a "extra" the method for this service is called in a new Thread.. What i do is this:

public void NotifyMembers(NotificatorClientDTO clientDto) {
if(clientDto == null)
    throw new ArgumentNullException("clientDto");


Thread t = new Thread( 
    () => {
    // go to database, verify business rules, etc...

    // At the end if it is ok, invoke the method that sends a email
}

t.Start()

}

If i create a unit test that instantiates the NotificatorService and call notifyMembers with some data, the code will throw an exception but only if i execute in a seperated thread.

The thread that i create is setted at foregronnd so the system don't destroy my process i suppose.

THe exception message is this:

SmtpException: Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack

I walk to 2 inner exceptions and i see this

_message "Thread was being aborted." string

Why this is happening?
What causes the thread to be aborted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

月隐月明月朦胧 2024-12-11 07:04:41

更改您的单元测试以采用 IMailService 或类似的依赖项。然后,您的网络应用程序单元测试不需要在发送电子邮件方面做任何真实的事情 - 它可以使用假的或模拟的。

当然,您需要创建 IMailService 的生产实现 - 并且单元测试可能仍然具有挑战性,但至少您将唯一 em> 对测试邮件处理感兴趣,这意味着您可以稍微改变限制。

您可以对线程创建方面执行相同的操作。基本上,尝试将代码中的“讨厌的部分”(与邮件服务和线程交互)与您想要测试的真实逻辑分开。

Change your unit test to take an IMailService or something similar as a dependency. Then your web application unit test doesn't need to do anything real in terms of sending emails - it can use a fake or a mock.

You then need to create a production implementation of IMailService of course - and unit testing that may still be challenging, but at least you'll then be only interested in testing mail handling, which means you may be able to change the constraints somewhat.

You can potentially do the same for the thread creation side of things. Basically, try to separate out the "nasty bits" of your code (which interact with mail services and threads) from the real logic you want to test.

流绪微梦 2024-12-11 07:04:41

正如您在问题标题中指定的那样,这看起来像是集成测试而不是单元测试。

尝试使用以下内容将 App.config 添加到 Tests.Assembly 项目,看看是否有帮助:(使用 ApartmentState=MTA 和 ApartmentState=STA

<?xml version="1.0" encoding="utf-8"?>

<configuration>
    <configSections>
        <sectionGroup name="NUnit">
            <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
        </sectionGroup>
    </configSections>

    <NUnit>
        <TestRunner>
            <add key="ApartmentState" value="STA" />
        </TestRunner>
    </NUnit>
</configuration>

This is looks like an Integration Test rather Unit Test as you've specified in question Title.

Try out to add App.config to the Tests.Assembly project with following content and see whether it helps: (play with ApartmentState=MTA and ApartmentState=STA)

<?xml version="1.0" encoding="utf-8"?>

<configuration>
    <configSections>
        <sectionGroup name="NUnit">
            <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
        </sectionGroup>
    </configSections>

    <NUnit>
        <TestRunner>
            <add key="ApartmentState" value="STA" />
        </TestRunner>
    </NUnit>
</configuration>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文