在Task.Run中调用了验证Mock方法

本文关键字:验证 Mock 方法 调用 Task Run | 更新日期: 2023-09-27 18:05:40

当方法本身在传递给Task.Run的委托中调用时,我如何验证在模拟上调用了方法?当mock.Verify被调用时,任务还没有执行。

我在mock.Verify之前尝试过await Task.Delay,但这似乎使测试运行器挂起。

使用Task.Run的原因是为了卸载逻辑,以防止攻击者能够在执行时区分电子邮件地址是否存在于系统中。

using System.Threading.Tasks;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace AsyncTesting
{
    class MyController : Controller
    {
        public IEmailService EmailService { get; set; }
        public MyController(IEmailService emailService)
        {
            EmailService = emailService;
        }
        public ViewResult BeginPasswordReset(string emailAddress)
        {
            BeginPasswordResetAsync(emailAddress);
            return View();
        }
        private Task BeginPasswordResetAsync(string emailAddress)
        {
            return Task.Run(delegate
            {
                EmailService.Send(emailAddress);
            });
        }
    }
    internal interface IEmailService
    {
        void Send(string emailAddress);
    }
    internal class MyControllerTests
    {
        [TestMethod]
        public void BeginPasswordReset_SendsEmail()
        {
            var mockEmailService = new Mock<IEmailService>();
            var controller = new MyController(mockEmailService.Object);
            const string emailAddress = "email@domain.com";
            controller.BeginPasswordReset(emailAddress);
            mockEmailService.Verify(es=>es.Send(emailAddress));
        }
    }
}

在Task.Run中调用了验证Mock方法

在您的任务中,您可以设置一个ManualResetEvent(我们的测试代码阻塞使用类似的东西):

Assert.IsTrue(yourEvent.WaitForOne(TimeSpan.FromSecond(<max time you want to wait>), "the event failed to run");

:

public void BeginPasswordReset_SendsEmail()
{
    const string emailAddress = "email@domain.com";
    ManualResetEvent sendCalled= new ManualResetEvent(false);
    var mockEmailService = new Mock<IEmailService>();
    mockEmailService.Setup(m => m.Send(emailAddress)).Callback(() =>
    {
        sendCalled.Set();
    });
    var controller = new MyController(mockEmailService.Object);
    controller.BeginPasswordReset(emailAddress);
    Assert.IsTrue(sendCalled.WaitOne(TimeSpan.FromSeconds(3)), "Send was never called");
    mockEmailService.Verify(es => es.Send(emailAddress));
}

一些快速的研究,看起来这是可能与MSTest。例如

[TestMethod]
public async Task BeginPasswordResetAsync();
{
    await BeginPasswordResetAsync("emailAddress");
    mockEmailService.Verify...
}