Skip to content
Home » Writing Unit Test for SMTP Component

Writing Unit Test for SMTP Component

I was working on a notification system that allows users to subscribe an email notification based on the status of the database record. An email will be sent to the destination whenever the status is satisfied.

As the system is providing various of email templates for users to choose when they’re defining the subscription. So the challenge to the development team is writing the unit test for each template and ensure the code coverage is more than 90% according to the DevOps strategy.

Writing this post, I would like to share the experience to write the unit tests for SMTP and how to perform the system integration test (SIT) without Exchange Email Server.

I. Writing Unit Tests For SMTP

As in the email template, I allow users to add some predefined parameters into email subject and body as the sample below:

  •  [DateTime]: before delivery email to destinations the system will transform this token to current date time.
  • [RecordId]: the system will pick up the primary key value of the record and replace to this token.
  • [CreatedBy] or [UpdatedBy]: if these tokens are in email subject it will be transformed to account email from active directory. If it is in email body then will be transferred to account name instead.

The requirement of the unit test for this system is able to verify not only template transformation but also the SMTP communication in order to limit the number of the code issues bugs leaking to SIT and UAT.

I found a useful open source library named netDumbster allows to simulate an SMTP service for developers to write the unit tests for SMTP module. This module allows running the unit tests in any build server without any additional installation needed.

Below is the source code for a sample notification service

public class NotificationService{
    public void NotifyTo(string status, params string[] Emails)
    {
        var email = new MailMessage
        {
            Subject = $"This is the notification for status {status}",
            Body = @"Dear All
This is notification email deom drunkcoding.net, pleasse ignore it if you are developers.
Thanks."
        };
        foreach (var m in Emails)
            email.To.Add(m);
           
        new SmtpClient().Send(email);
    }
}

And here is the unit test for this service.

[TestClass()]
public class NotificationServiceTests
{
    private static SimpleSmtpServer _smtpServer;
    [AssemblyInitialize]
     public static void AppDomainSetup(TestContext context)
        => _smtpServer = SimpleSmtpServer.Start(25);
    [AssemblyCleanup]
    public static void Cleaup() => _smtpServer.Stop();
    [TestMethod()]
    public void NotifyTo_Approved_Test()
    {
        _smtpServer.ClearReceivedEmail();
        new NotificationService().NotifyTo("Approved", "drunkcoding@outlook.com");
        var email = _smtpServer.ReceivedEmail.First();
        Assert.AreEqual(email.FromAddress.Address, "unittest@drunkcoding.net");
        Assert.AreEqual(email.ToAddresses.First().Address, "drunkcoding@outlook.com");
        Assert.IsTrue(email.Data.Contains("Subject: This is the notification for status Approved"));
        Assert.IsTrue(email.MessageParts[0].BodyData.Contains("This is notification email demo drunkcoding.net, pleasse ignore it if you are developers."));
    }
    [TestMethod()]
    public void NotifyTo_Rejected_Test()
    {
        _smtpServer.ClearReceivedEmail();
        new NotificationService().NotifyTo("Rejected", "drunkcoding@outlook.com");
        var email = _smtpServer.ReceivedEmail.First();
        Assert.AreEqual(email.FromAddress.Address, "unittest@drunkcoding.net");
        Assert.AreEqual(email.ToAddresses.First().Address, "drunkcoding@outlook.com");
        Assert.IsTrue(email.Data.Contains("Subject: This is the notification for status Rejected"));
        Assert.IsTrue(email.MessageParts[0].BodyData.Contains("This is notification email demo drunkcoding.net, pleasse ignore it if you are developers."));
    }
}

The configuration of the Unit Test project.

<system.net>
   <mailSettings>
     <smtp from="unittest@drunkcoding.net">
       <network host="localhost"/>
     </smtp>
   </mailSettings>
</system.net>

You may face below issue when using this library. Because the SMTP is not stopping property and the unit tests process is still running.

To resolve this issue just simply force stop below processes in the Task Manager and then run the unit tests again.

Here is the result when running the auto build on the VSTS.

I would recommend using [AssemblyInitialize] and [AssemblyCleanup] to start and stop the SMTP emulator instead of [TestInitialize] and [TestCleanup] because start and stop the emulator is taking time and sometimes the SMTP is not stopped properly and keep holding the port 25 so that the next instance is not able to initialize for the second test method.

 

II. The SMTP Emulator for SIT and UAT.

There are so many reasons that we don’t want The testers using the real Product exchange server to perform the SIT or UAT testing. I don’t want to list out the reason here. However, if you are looking for an alternative solution that allows testers testing the SMTP without exchange server then there is a free and open source tool for that purposes.

The Papercut is an SMTP emulator that saving the incoming emails to a location instead of delivery to the real destinations. This tool provides a WinForms application that allows tester verify the email directly.

There is a Papercut service allows you host the SMTP emulator on to a server in the test environment and share across to all application.

III. Source Code

You can download the demo source code here.

8 thoughts on “Writing Unit Test for SMTP Component”

  1. I don抰 even know how I finished up right here, however I assumed this submit was once great. I don’t understand who you’re but certainly you are going to a famous blogger when you are not already 😉 Cheers!

  2. Have you ever thought about publishing an ebook or guest authoring on other websites? I have a blog centered on the same ideas you discuss and would love to have you share some stories/information. I know my viewers would enjoy your work. If you are even remotely interested, feel free to send me an e-mail.

  3. Hello there, just became alert to your blog through Google, and found that it’s really informative. I抦 gonna watch out for brussels. I will appreciate if you continue this in future. Many people will be benefited from your writing. Cheers!

  4. I was excited to discover this website. I want to to thank you for your time for this wonderful read!! I definitely liked every part of it and i also have you book-marked to look at new things on your website.

  5. Hey! This is my first comment here so I just wanted to give a quick shout out and tell you I really enjoy reading through your blog posts. Can you recommend any other blogs/websites/forums that go over the same topics? Thanks a ton!

  6. Im very pleased to find this site. I need to to thank you for ones time for this particularly fantastic read!! I definitely really liked every part of it and I have you bookmarked to see new information on your site.

Leave a Reply

Your email address will not be published.