¿Cómo puedo verificar que se llamó a un método en un simulacro cuando el método mismo se llama en un delegado pasado a Task.Run ? Cuando se llama a mock.Verify , la tarea aún no se ha ejecutado.
Intenté await Task.Delay justo antes mock.Verify pero esto parece dejar colgado al corredor de prueba.
La razón para usar Task.Run es descargar la lógica para evitar que un atacante pueda diferenciar si la dirección de correo electrónico existe en el sistema en el momento de la ejecución.
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)); } } }En su tarea, puede configurar un ManualResetEvent (que nuestro código de prueba bloquea al usar algo como:
Assert.IsTrue(yourEvent.WaitForOne(TimeSpan.FromSecond(<max time you want to wait>), "the event failed to run");Me gusta esto:
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)); }Un poco de investigación rápida parece que es posible con MSTest. p.ej
[TestMethod] public async Task BeginPasswordResetAsync(); { await BeginPasswordResetAsync("emailAddress"); mockEmailService.Verify... }