Reputation: 13
I am writing unit test case for the below class Communication service. I have the below interface communicationservice .
I want to write the Nunit or unit test for the SendMail method which is present in the CommunicationService without sending mails. (smtpClient.Send(mailMessage))
```
public interface ISmtpClient
{
void Send(MailMessage message);
}
public class SmtpClientWrapper : ISmtpClient
{
public SmtpClientWrapper(SmtpClient client)
{
Client = client;
}
public SmtpClient Client { get; }
public void Send(MailMessage message)
{
Client.Send(message);
}
}
public interface ICommunicationService
{
bool SendMail(string mailSender, IEnumerable<string> recipients, IEnumerable<string> cc, string subject, string mailContent, string senderPass);
}
Implementation logic for the communication service parameter here are the details needed for Mail message class. for send mail public class CommunicationService : ICommunicationService { private readonly ILogger _logger; private readonly ISmtpClient _client; public CommunicationService( ILogger logger, ISmtpClient client) { _logger = logger; _client = client; // also read appsettings for the smtp client details } public bool SendMail(string mailSender, IEnumerable recipients, IEnumerable cc, string subject, string mailContent, string senderPass) { MailMessage mailMessage = new MailMessage { Subject = subject, Body = mailContent, From = new MailAddress(mailSender, "XXXX"), IsBodyHtml = true };
var recipientsList = recipients.ToList();
if (!recipientsList.Any())
{
_logger.LogWarning("Mail not sent, no recipients specified");
}
foreach (var address in recipientsList)
{
mailMessage.To.Add(address);
}
if (cc != null)
{
foreach (string address in cc)
{
mailMessage.CC.Add(address);
}
}
NetworkCredential networkCredential = new NetworkCredential(mailSender, senderPass);
try
{
var smtp = new SmtpClient
{
Host = "smtp.office365.com",
Port = 587,
EnableSsl = true,
UseDefaultCredentials = false,
Credentials = networkCredential,
DeliveryMethod = SmtpDeliveryMethod.Network,
Timeout = 20000,
};
var wrapper = new SmtpClientWrapper(smtp);
smtp.Send(mailMessage);
return true;
}
catch (Exception exception)
{
_logger.LogError(exception.Message, exception);
return false;
}
}
}
From the consumer i call the communication service send method with the details needed for Mail message.Passing here the parameters needed for MailMessage class
here is the code i have tried. Here is the unit test case
public void SendMail_SuccessfullySendsMail_ReturnsTrue()
{
// Arrange
var mailSender = "[email protected]";
var recipients = new List<string> { "[email protected]", "[email protected]" };
var cc = new List<string> { "[email protected]", "[email protected]" };
var subject = "Test Subject";
var mailContent = "Test Body";
var senderPass = "your-password";
MailMessage mail = new MailMessage()
{
Body = "ABC",
Subject = subject
};
var clientMock = new Mock<ISmtpClient>();
// clientMock.Setup(x => x.Send(mail));
// Create an instance of your MailSender class
var mailSenderInstance = new CommunicationService(logger.Object, clientMock.Object);
// Act
var result = mailSenderInstance.SendMail(mailSender, recipients, cc, subject, mailContent, senderPass);
Assert.IsTrue(result);
}
Here is the unit test case, but it not work . Authentication unsuccessful message i am getting from the nunit test case.
Upvotes: 1
Views: 1159
Reputation: 1664
You can rewrite your class like this and use SmtpClientWrapper in your production code:
public interface ISmtpClient
{
void Send(MailMessage message);
}
public class SmtpClientWrapper : ISmtpClient
{
public SmtpClientWrapper(SmtpClient client)
{
Client = client;
}
public SmtpClient Client { get; }
public void Send(MailMessage message)
{
Client.Send(message);
}
}
public class CommunicationService: ICommunicationService
{
private readonly ILogger _logger;
private readonly ISmtpClient _client;
public CommunicationService( ILogger logger, ISmtpClient client)
{
_logger = logger;
_client = client;
}
public bool SendMail(string mailSender, IEnumerable recipients, IEnumerable cc, string subject, string mailContent, string senderPass)
{
// validation part of the old method here
// use client from constructor
_client.Send(mailMessage);
}
}
Test method:
public void SendMail_SuccessfullySendsMail_ReturnsTrue()
{
// Arrange
var clientMock = new Mock<ISmtpClient>();
clientMock.Setup(x => x.Send(new MailMessage()));
var mailSender = "[email protected]";
var recipients = new List<string> { "[email protected]", "[email protected]" };
var cc = new List<string> { "[email protected]", "[email protected]" };
var subject = "Test Subject";
var mailContent = "Test Body";
var senderPass = "your-password";
// Create an instance of your MailSender class
var mailSenderInstance = new CommunicationService(logger.Object, smtpClient.Object);
// Act
var result = mailSenderInstance.SendMail(mailSender, recipients, cc, subject, mailContent, senderPass);
// Assert
Assert.IsTrue(result);
}
There is also another thread on mocking the SmtpClient (which may provide more elegant solution): How to mock/fake SmtpClient in a UnitTest?
Upvotes: 0