2015-07-30 2 views
4

Как проверить, что метод был вызван при макете, когда сам метод вызывается в делетете, переданном Task.Run? По времени mock.Verify называется Task еще не выполнен.Проверка метода Mock вызывалась внутри Task.Run

Я пробовал await Task.Delay как раз перед mock.Verify, но это, похоже, покидает тестовый бегун.

Причина использования 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 protected]"; 

      controller.BeginPasswordReset(emailAddress); 

      mockEmailService.Verify(es=>es.Send(emailAddress)); 
     } 
    } 
} 
+0

Я не уверен в MSTest, но с NUnit вы можете использовать метод асинхронного тестирования и ждать метода BeginPasswordResetAsync. Задача завершится после ожидания. Изучите асинхронные тесты с помощью MSTest. – Padraic

+1

'Причина использования Task.Run ...' Извините, но это плохая причина для того, чтобы ввести такой пункт ошибки в ваше приложение. 'Task.Run' чрезвычайно опасен для ASP.NET; по крайней мере, используйте 'HostingEnvironment.QueueBackgroundWorkItem'. –

+0

Спасибо @ StephenCleary, я прочитаю ваши комментарии по теме http://blog.stephencleary.com/2013/10/taskrun-etiquette-and-proper-usage.html –

ответ

4

В вашей задаче вы можете установить 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 protected]"; 

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

Это прекрасно, только то, что я искал. –

1

быстрых исследований он выглядит, как он возможно с использованием MSTest, например

[TestMethod] 
public async Task BeginPasswordResetAsync(); 
{ 
    await BeginPasswordResetAsync("emailAddress"); 

    mockEmailService.Verify... 
} 
+0

Я пробовал это, и он, казалось, повесил тестового бегуна. Также фактический асинхронный метод является приватным для контроллера. –

Смежные вопросы