验证在Task.Run内部调用了Mock方法 [英] Verifying Mock method was called inside Task.Run

查看:87
本文介绍了验证在Task.Run内部调用了Mock方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当在传递给Task.Run的委托中调用方法本身时,如何验证方法是否已在模拟对象上调用?到mock.Verify被调用时,任务仍然没有执行.

How can I verify that a method was called on a mock when the method itself is called in a delegate passed to Task.Run? By time mock.Verify is called the Task still hasn't executed.

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

I have tried await Task.Delay just before mock.Verify but this seems to leave the test runner hanging.

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

The reason for using Task.Run is to offload the logic to prevent an attacker from being able to differentiate whether the email address exists in the system by the time to execute.

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));
        }
    }
}

推荐答案

在您的任务中,您可以设置一个ManualResetEvent(我们的测试代码会使用类似以下的代码来阻止该事件:

In your task you could set a ManualResetEvent (which our test code blocks on using something like:

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));
}

这篇关于验证在Task.Run内部调用了Mock方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆