提问人:Bash 提问时间:11/15/2023 最后编辑:Bash 更新时间:11/16/2023 访问量:108
如何编写单元测试用例和模拟 SmtpClient 发送邮件
How to write unit test case and Mock SmtpClient Send mail
问:
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);
}
通信服务参数的实现逻辑 以下是 Mail 消息类所需的详细信息。 用于发送邮件 公共类 CommunicationService:ICommunicationService { private readonly ILogger _logger; private 只读 ISmtpClient _client; 公共通信服务( ILogger 记录器、ISmtpClient 客户端) { _logger = 记录器; _client = 客户端; 另请阅读 AppSettings 了解 SMTP 客户端详细信息 } public bool SendMail(字符串 mailSender, IEnumerable recipients, IEnumerable cc, string subject, string mailContent, string senderPass) { MailMessage mailMessage = 新邮件 { 主题 = 主题, 正文 = mailContent, From = new MailAddress(mailSender, “XXXX”), IsBodyHtml = 真 };
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> { "cc[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.
答:
0赞
vhr
11/15/2023
#1
您可以像这样重写类,并在生产代码中使用 SmtpClientWrapper:
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);
}
}
测试方法:
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);
}
还有另一个关于模拟 SmtpClient 的线程(它可能会提供更优雅的解决方案):如何在 UnitTest 中模拟/伪造 SmtpClient?
评论
0赞
Bash
11/15/2023
消息:System.NotSupportedException:不支持的表达式:x => x.Send(mail) 不可重写的成员(此处:SmtpClient.Send)不得用于设置/验证表达式。..我收到此消息
0赞
vhr
11/15/2023
更新了我的答案,以便它使用接口和包装类
0赞
Bash
11/15/2023
主机 =“smtp.office365.com”,端口 = 587,EnableSsl = true,UseDefaultCredentials = false,凭据 = networkCredential,DeliveryMethod = SmtpDeliveryMethod.Network,超时 = 20000 在这种情况下,我怎样才能在这里绑定这些属性
0赞
vhr
11/15/2023
在生产代码中,您可以执行以下操作: 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);var service = new CommunicationService(null, wrapper);
0赞
Bash
11/16/2023
尝试激活“xxxxx.xxxxx.xxxxx.xxxxx.xxxxx.Email.SmtpClientWrapper”时,无法解析类型为“System.Net.Mail.SmtpClient”的服务,编译时出现此错误
评论
ISmtpClient