How to mock/fake SmtpClient in a UnitTest?

大兔子大兔子 提交于 2020-01-01 04:16:27

问题


I want to use it to fake System.Net.Mail.SmtpClient in a MS-Test UnitTest. Therefor I added a Fakes Assembmly of System.dll. Then I create a ShimsContext and a StubSmtpClient.

using (ShimsContext.Create())
{
   StubSmtpClient client = new StubSmtpClient();               
}

But what do I do with it? The ultimate goal would be to write a Test which expects that the send Method is called with a object of MailMessage.


回答1:


You can create an interface which will expose functions that will be used from SmtpClient

public interface ISmtpClient   
    {
        void Send(MailMessage mailMessage);
    }

Then create your Concrete class which will do real job.

 public class SmtpClientWrapper : ISmtpClient
    {
        public SmtpClient SmtpClient { get; set; }
        public SmtpClientWrapper(string host, int port)
        {
            SmtpClient = new SmtpClient(host, port);
        }
        public void Send(MailMessage mailMessage)
        {
            SmtpClient.Send(mailMessage);
        }
    }

In your test method now you can mock it and use like;

[TestMethod()]
        public void SendTest()
        {
            Mock<ISmtpClient> smtpClient = new Mock<ISmtpClient>();
            SmtpProvider smtpProvider = new SmtpProvider(smtpClient.Object);
            string @from = "from@from.com";
            string to = "to@to.com";
            bool send = smtpProvider.Send(@from, to);
            Assert.IsTrue(send);
        }



回答2:


This isn't really an answer to your question, but an alternative aproach:

In the app.config, set up the smtp settings to deliver the mails as files to a local directory instead. Then you can load the file and check the contents in your assert section.

You'll have to write a bit more code for the assertion (or preferably create some helper functions) but you won't have to do anything that affects the production code.




回答3:


Another alternative is to use nDumbster:

Install-Package nDumbster

It runs an Smtp server in memory, which you can then verify against. It turns it more into an integration test, but generally those are higher value than unit tests, as you want to test the SmtpClient usage is also correct.




回答4:


A version of this answer by Teoman shipahi that correctly disposes of the SmtpClient.

First make ISmtpClient inherit IDisposable:

public interface ISmtpClient : IDisposable
{
    void Send(MailMessage mailMessage);
}

Then implement IDisposable in the SmtpClientWrapper class:

public class SmtpClientWrapper : ISmtpClient
{
    private bool disposed;
    private readonly SmtpClient smtpClient;

    public SmtpClientWrapper(string host, int port)
    {
        smtpClient = new SmtpClient(host, port);
    }

    ~SmtpClientWrapper()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                smtpClient?.Dispose();
            }
            disposed = true;
        }
    }

    protected void CheckDisposed()
    {
        if (disposed)
        {
            throw new ObjectDisposedException(nameof(SmtpClientWrapper));
        }
    }

    public void Send(MailMessage mailMessage)
    {
        CheckDisposed();
        smtpClient.Send(mailMessage);
    }
}

For this version of SmtpClientWrapper, I have removed the SmtpClient property to avoid the problem of the SmtpClient objects not being disposed of when replaced in setter of the SmtpClient property.



来源:https://stackoverflow.com/questions/19971364/how-to-mock-fake-smtpclient-in-a-unittest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!