如何解决Moq 为什么模拟方法返回 null 并测试直到通过? 设置阶段验证阶段
我正在尝试模拟下面的两个接口。
Mock<IEmailSender> emailSender = new Mock<IEmailSender>();
Mock<IEmailTemplate> emailTemplate = new Mock<IEmailTemplate>();
这里是设置
emailTemplate.Setup(x => x.GetForgotPasswordTemplate(It.IsAny<EmailTemplateviewmodel>())).Returns(It.IsAny<string>());
emailSender.Setup(x => x.SendEmailAsync(It.IsAny<SendEmailviewmodel>(),default)).ReturnsAsync(It.IsAny<SendEmailResultviewmodel>());
这是调用的控制器操作。
[EnableCors(PolicyName = "AllowClientAccess")]
[HttpGet("Forgot")]
public async Task<IActionResult> ForgotPassword([FromQuery] string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user != null)
{
//MOQ file path not found
EmailTemplateviewmodel model = new EmailTemplateviewmodel();
model.Email = email;
model.RecipientName = user.UserName;
var message = _emailTemplate.GetForgotPasswordTemplate(model);
SendEmailviewmodel sendEmailviewmodel = new SendEmailviewmodel();
sendEmailviewmodel.RecipientName = user.UserName;
sendEmailviewmodel.RecipientEmail = user.Email;
sendEmailviewmodel.Subject = "ForgotPassword";
sendEmailviewmodel.Body = message;
await _emailSender.SendEmailAsync(sendEmailviewmodel);
return Ok(AddSuccess("Check your email","Forgot Password"));
}
ModelState.AddModelError("Forgot Password","Unable to send email");
return BadRequest(ModelErrors());
}
这一行返回空
var message = _emailTemplate.GetForgotPasswordTemplate(model);
public string GetForgotPasswordTemplate(EmailTemplateviewmodel model)
{
try
{
var utcNow = DateTime.Now;
if (_testemailTemplate == null)
if (File.Exists("Helpers/Templates/ForgotPasswordEmail.template"))
_testemailTemplate = ReadPhysicalFile("Helpers/Templates/ForgotPasswordEmail.template");
var appUrl = _configuration.GetSection("ApplicationUrl").Value +
"/reset-password?&email=" + model.Email;
var emailMessage = _testemailTemplate
.Replace("{user}",model.RecipientName)
.Replace("{testDate}",utcNow.ToString(CultureInfo.InvariantCulture))
.Replace("{appUrl}",appUrl);
return emailMessage;
}
catch (Exception e)
{
Log.Warning(e,"Email error");
throw;
}
}
这一行也返回空
await _emailSender.SendEmailAsync(sendEmailviewmodel);
public Task<SendEmailResultviewmodel> SendEmailAsync(SendEmailviewmodel model,SmtpConfig config = default)
{
model.IsHtml = true;
var from = new MailBoxAddress(_config.FromName,_config.FromEmail);
var to = new MailBoxAddress(model.RecipientName,model.RecipientEmail);
return SendEmailAsync(@from,new[] {to},model.Body,config,model.IsHtml);
}
这里是测试
[Theory]
[InlineData("stephen@kaizenappz.com")]
public async Task WhenAUserForgetsPasswordAHttpStatusCode200ShouldBeReturnedAsync(string email)
{
var confirmUser = await Controller.ForgotPassword(email);
var result = confirmUser as OkObjectResult;
var actual = (HttpStatusCode)result?.StatusCode.Value;
var expected = HttpStatusCode.OK;
Assert.AreEqual(expected,actual);
}
但是测试通过了,我想知道为什么这两种方法都返回 null 以及为什么即使它返回 null 测试也通过了。我如何让这些东西返回?
我不明白的一件事是什么时候使用 It.Any 并且只传递带有一些测试数据的普通对象。如果我使用 It.Any 并且我需要将模型传递到我的控制器操作中,我应该如何检查用户是否存在?
解决方法
设置阶段
每当您需要模拟接口方法时,请尝试在设置过程中放任自流。
换句话说,允许接收任何参数:
const string mockedForgotPwdTemplate = "...";
emailTemplate
.Setup(template => template.GetForgotPasswordTemplate(It.IsAny<EmailTemplateViewModel>()))
.Returns(mockedForgotPwdTemplate);
如果你的返回值取决于参数
然后使用 Returns
的重载,它接受一个函数:
const string mockedTemplateWithSubject = "...";
const string mockedTemplateWithoutSubject = "...";
emailTemplate
.Setup(template => template.GetForgotPasswordTemplate(It.IsAny<EmailTemplateViewModel>()))
.Returns((EmailTemplateViewModel vm) => !string.IsNullOrEmpty(vm.Subject) ? mockedTemplateWithSubject : mockedTemplateWithoutSubject);
验证阶段
在断言期间尽量具体。
如果您有权访问该参数,则将其传递给 Verify
:
var mockedViewTemplate = new EmailTemplateViewModel { ... };
emailTemplate
.Verify(template => template.GetForgotPasswordTemplate(mockedViewTemplate),Times.Once);
请记住,moq 使用引用检查来确定 expected
和 actual
参数是否相同。如果您没有对此参数的引用,则应使用 It.Is<T>
:
const string expectedSubject = "ForgotPassword";
emailTemplate
.Verify(template => template.GetForgotPasswordTemplate(
It.Is<EmailTemplateViewModel>(vm => expectedSubject == vm.Subject),Times.Once);
或者如果您希望对多个属性进行断言,则:
private bool AssertViewModel(EmailTemplateViewModel actualVM,string expectedSubject,string expectedRecipientName)
{
Assert.Equal(expectedSubject,actualVM.Subject);
Assert.Equal(expectedRecipientName,actualVM.RecipientName);
return true;
}
//...
const string expectedSubject = "ForgotPassword",expectedRecipent = "...";
emailTemplate
.Verify(template => template.GetForgotPasswordTemplate(
It.Is<EmailTemplateViewModel>(vm => this.AssertViewModel(vm,expectedSubject,expectedRecipient)),Times.Once);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。