2013-04-04 68 views
8

我想測試下的單元測試執行的延遲:使用模擬起訂量

protected IHealthStatus VerifyMessage(ISubscriber destination) 
{ 
    var status = new HeartBeatStatus(); 

    var task = new Task<CheckResult>(() => 
    { 
     Console.WriteLine("VerifyMessage(Start): {0} - {1}", DateTime.Now, WarningTimeout); 
     Thread.Sleep(WarningTimeout - 500); 
     Console.WriteLine("VerifyMessage(Success): {0}", DateTime.Now); 
     if (CheckMessages(destination)) 
     { 
      return CheckResult.Success; 
     } 

     Console.WriteLine("VerifyMessage(Pre-Warning): {0} - {1}", DateTime.Now, ErrorTimeout); 
     Thread.Sleep(ErrorTimeout - 500); 
     Console.WriteLine("VerifyMessage(Warning): {0}", DateTime.Now); 
     if (CheckMessages(destination)) 
     { 
      return CheckResult.Warning; 
     } 

     return CheckResult.Error; 
    }); 

    task.Start(); 

    task.Wait(); 
    status.Status = task.Result; 

    return status; 
} 

具有以下的單元測試:

public void HeartBeat_Should_ReturnWarning_When_MockReturnsWarning() 
{ 
    // Arrange 
    var heartbeat = new SocketToSocketHeartbeat(_sourceSubscriber.Object, _destinationSubscriber.Object); 
    heartbeat.SetTaskConfiguration(this.ConfigurationHB1ToHB2_ValidConfiguration()); 

    // Simulate the message being delayed to destination subscriber. 
    _destinationSubscriber.Setup(foo => foo.ReceivedMessages).Returns(DelayDelivery(3000, Message_HB1ToHB2())); 

    // Act 
    var healthStatus = heartbeat.Execute(); 

    // Assert 
    Assert.AreEqual(CheckResult.Warning, healthStatus.Status); 
} 

Message_HB1ToHB2()只返回的字符串人物和「延遲交貨」的方法是

private List<NcsMessage> DelayDelivery(int delay, string message) 
{ 
    var sent = DateTime.Now; 
    var msg = new NcsMessage() 
    { 
     SourceSubscriber = "HB1", 
     DestinationSubscriber = "HB2", 
     SentOrReceived = sent, 
     Message = message 
    }; 

    var messages = new List<NcsMessage>(); 
    messages.Add(msg); 

    Console.WriteLine("DelayDelivery: {0}", DateTime.Now); 
    Thread.Sleep(delay); 
    Console.WriteLine("DelayDelivery: {0}", DateTime.Now); 

    return messages; 
} 

我使用起訂量爲模擬框架和MSTest的作爲TESTIN g框架。每當我運行單元測試,我得到以下的輸出:

DelayDelivery: 04/04/2013 15:50:33 
DelayDelivery: 04/04/2013 15:50:36 
VerifyMessage(Start): 04/04/2013 15:50:36 - 3000 
VerifyMessage(Success): 04/04/2013 15:50:38 

除了明顯的「代碼味道」上述方法所使用Thread.sleep代碼,單元測試的結果不是我想要去完成。

任何人都可以提出一個更好/準確的方法來使用Moq框架來模擬消息的「傳遞」延遲。我遺漏了一些「膠水」代碼,只包含相關部分。讓我知道,如果我遺漏了某些東西,使你無法理解這個問題。

+3

你最好創建一個例子(除你以外)可以實際運行,突出你想要完成的事情。這裏沒有任何東西可以在沒有做大量額外工作的情況下複製和運行。 – 2013-04-04 20:34:37

回答

27

如果你想有一個起訂量模擬眼睜睜地對什麼也不做,而你可以使用一個回調:

Mock<IFoo> mockFoo = new Mock<IFoo>(); 
mockFoo.Setup(f => f.Bar()) 
     .Callback(() => Thread.Sleep(1000)) 
     .Returns("test"); 

string result = mockFoo.Object.Bar(); // will take 1 second to return 

Assert.AreEqual("test", result); 

我試過在LinqPad,如果你調整Thread.Sleep()的執行時間相應地變化。

+0

回調()方法是我錯過了...我更新了單元測試使用,單元測試現在「嘲笑」延遲正確...謝謝! – 2013-04-05 13:06:17

+4

這似乎並不適用於我,我認爲回調是在結果由Moq – 2016-05-19 14:09:17

+0

返回後執行的我同意@DanDinu - 如果同時運行兩個調用Bar(),那麼兩個Callback在兩個Bar()完成後執行*。 – OffHeGoes 2016-06-22 09:57:26

0

我不能讓起訂量版的工作,所以我最終作出這樣的事情:

一個小例子使用的WaitHandle:

[TestFixture] 
public class EventWaitHandleTests 
{ 
    class Worker { 
     private volatile bool _shouldStop; 
     public EventWaitHandle WaitHandleExternal; 

     public void DoWork() 
     { 
      while (!_shouldStop) 
      { 
       Console.WriteLine("worker thread: working..."); 
       Thread.Sleep(1000); 
       WaitHandleExternal.Set(); 
      } 
     } 

     public void RequestStop() 
     { 
      _shouldStop = true; 
     } 

    } 

    [Test] 
    public void WaitForHandleEventTest() 
    { 
     EventWaitHandle _waitHandle = new AutoResetEvent (false); // is signaled value change to true 

     // start a thread which will after a small time set an event 
     Worker workerObject = new Worker(); 
     workerObject.WaitHandleExternal = _waitHandle; 
     Thread workerThread = new Thread(workerObject.DoWork); 

     // Start the worker thread. 
     workerThread.Start(); 

     Console.WriteLine ("Waiting..."); 
     _waitHandle.WaitOne();    // Wait for notification 
     Console.WriteLine ("Notified"); 

     // Stop the worker thread. 
     workerObject.RequestStop(); 

    } 

} 
6

當你設置你的模擬你可以告訴線程睡在返回func:

Mock<IMyService> myService = new Mock<IMyService>(); 

myService.Setup(x => x.GetResultDelayed()).Returns(() => { 
    Thread.Sleep(100); 
    return "result"; 
});