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("xxx@gmail.com");
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 crea开发者_StackOverflow社区te 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?
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.
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>
精彩评论