How to mock/fake SmtpClient in a UnitTest?

前端 未结 4 1592
野的像风
野的像风 2020-12-30 03:38

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<

相关标签:
4条回答
  • 2020-12-30 03:58

    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.

    0 讨论(0)
  • 2020-12-30 03:58

    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.

    0 讨论(0)
  • 2020-12-30 04:03

    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);
            }
    
    0 讨论(0)
  • 2020-12-30 04:08

    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.

    0 讨论(0)
提交回复
热议问题