简体   繁体   中英

How to mock new instance using moq

I want to test the below method using moq by mocking both MailMessage and SmptpClient

public void SendEmail(string emailAddress, string subject, string body)
{
    using (var mail = new MailMessage(NoReplyEmailAddress, emailAddress))
    {
        mail.Subject = subject;
        mail.Body = body;
        mail.IsBodyHtml = true;

        using (var client = new SmtpClient())
        {
            client.Host = SmtpHost;
            client.Port = SmtpPort;
            client.DeliveryMethod = SmtpDeliveryMethod.Network;
            client.Send(mail);
        }
    }
}

And My test method is :

public void TestSendEmail()
{
    Mock<MailMessage> mailMessageMock = new Mock<MailMessage>();
    MailMessage message = (MailMessage)mailMessageMock.Setup(m => new MailMessage()).Returns(mailMessageMock.Object);
    Mock<SmtpClient> smtpClientMock = new Mock<SmtpClient>();
    smtpClientMock.Setup(s => new SmtpClient()).Returns(smtpClientMock.Object);

    EmailService emailService = new EmailService();
    emailService.SendEmail("tester@gmail.com","Test Mail", "Content");

    mailMessageMock.Verify(m => m.Subject);
    mailMessageMock.Verify(m => m.Body);
    mailMessageMock.Verify(m => m.IsBodyHtml);

    smtpClientMock.Verify(s=>s.Host);
    smtpClientMock.Verify(s=>s.Port);
    smtpClientMock.Verify(s=>s.DeliveryMethod);
    smtpClientMock.Verify(s=>s.Send(message));
}

But its not working is there anyway to do this?

Your code is untestable, you can fix it in several ways, eg:

Create abstractions over SmtpClient and MailMessage types:

public interface ISmtpClient
{
    void Send(MailMessage msg, string host, int port, SmtpDeliveryMethod deliveryMethod);
}

public interface IMailMessageComposer
{
    MailMessage Create(string noReplyEmailAddress, string emailAddress, string subject, string body, bool isHtml);
}

Create very simple implementation with your logic:

public class MySmtpClient : ISmtpClient
{
    public void Send(MailMessage msg, string host, int port, SmtpDeliveryMethod deliveryMethod)
    {
        using (var client = new SmtpClient())
        {
            client.Host = host;
            client.Port = port;
            client.DeliveryMethod = deliveryMethod;
            client.Send(msg);
        }
    }
}

public class MailMessageComposer : IMailMessageComposer
{
    public MailMessage Create(string noReplyEmailAddress, string emailAddress, string subject, string body, bool isHtml)
    {
        return new MailMessage(noReplyEmailAddress, emailAddress)
        {
            Subject = subject,
            Body = body,
            IsBodyHtml = isHtml
        };
    }
}

And then inject these dependencies to your class which is responsible for sending emails:

public class EmailService
{
    private readonly ISmtpClient _smtpClient;
    private readonly IMailMessageComposer _mailMessageComposer;

    public EmailService(ISmtpClient smtpClient, IMailMessageComposer mailMessageComposer)
    {
        _smtpClient = smtpClient;
        _mailMessageComposer = mailMessageComposer;
    }

    public void SendEmail(string emailAddress, string subject, string body)
    {
        var message = _mailMessageComposer.Create(NoReplyEmailAddress, emailAddress, subject, body, true);
        _smtpClient.Send(message, SmtpHost, SmtpPort, SmtpDeliveryMethod.Network);
    }
}

And now your are able to test SmtpClient and MailMessage separately.

Tests:

public void Create_MailMessage()
{
    var mailComposer = new MailMessageComposer();

    var mailMessage = mailComposer.Create("noReply@example.com", "email@example.com", "subject", "body", true);

    Assert.Equal("noReply@example.com", mailMessage.Subject);
    Assert.Equal("body", mailMessage.Body);
    //etc.
}

For mocking MailMessage and SMTPClient classes they should be injected in EmailServiceConstructor

  public class EmailService {
   //Constructor  
   public EmailService(MailMessage mailmsgObj, SmtpClient smtpClient)
   {

   }

 }

Then you can inject the mocked classes for MailMessage and smtpclient while creating EmailServiceObject in your testcase

    Mock<MailMessage> mailMessageMock = new Mock<MailMessage>();
    MailMessage message = (MailMessage)mailMessageMock.Setup(m => new     MailMessage()).Returns(mailMessageMock.Object);
    Mock<SmtpClient> smtpClientMock = new Mock<SmtpClient>();
    smtpClientMock.Setup(s => new SmtpClient()).Returns(smtpClientMock.Object);

    EmailService emailService = new EmailService(mailMessageMock.object,smtpClientMock.object);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM