2013-06-19 59 views
0

有誰知道是否可以使用Rhino Mocks檢查某個方法是否在給定的時間段內被調用?使用Rhino Mocks聲明在給定時間段內調用方法

這是我想要寫一個單元測試代碼:

while (true) 
    if (TimeoutErrorStopwatch.IsRunning && 
     TimeoutErrorStopwatch.ElapsedMilliseconds > timeoutErrorTime) 
    { 
     someClass.HandleError(); 
    } 
    else 
     Thread.Sleep(10); 

我想寫一個單元測試,確保錯誤被​​檢查的HandleError方法是否被調用抓獲。這個循環運行在自己的後臺線程上,所以我想知道是否有方法來斷言該方法是通過約束來調用的,以便繼續檢查並斷言在給定時間內調用該方法。東西的效果:

someClass.AssertWasCalled(s => s.HandleError()).Within(10); 

我目前的解決辦法是我只需調用Thread.Sleep(10)然後用AssertWasCalled,但如果這樣的事情在犀牛嘲笑支持我不知道。

謝謝!

------編輯------

在註釋的光,我寫了檢查,看看是否該方法被調用,直到給定的時間限制已經達到一個擴展方法,睡在失敗的通話之間。實際上,我已經嘲笑了定時器(在實際應用中,超時設置爲30分鐘,而在我的測試中,我設置了100毫秒或更少的模擬值)。我以爲我會張貼我的擴展,以防有人在這篇文章中發現。

public static void AssertWasCalledWithin<T>(this T stub, Action<T> action, long milliseconds) 
    { 
     var timer = Stopwatch.StartNew(); 
     var e = new Exception(); 
     while (timer.ElapsedMilliseconds <= milliseconds) 
      try 
      { 
       stub.AssertWasCalled(action); 
       return; 
      } 
      catch (ExpectationViolationException exc) 
      { 
       e = exc; 
       Thread.Sleep(1); 
      } 

     throw new ExpectationViolationException(
      string.Format(
       "The following expectation was not met within the " + 
       "given time limit of {0} milliseconds: {1}", 
       milliseconds, e.Message)); 
    } 
+3

除了實際睡在測試中,測試這些東西的標準方法是模擬定時源本身。 –

+0

如果一切都在你的控制之下,考慮添加一個時間接口並控制它。當你可以通過一個界面控制時間的流逝時,你可以消除這種依賴關係,並且測試不會變得脆弱。 – Johannes

回答

1

我與WhenCalled擴展方法組合使用的ManualResetEvent這種類型的測試:

ManualResetEvent mre = new ManualResetEvent(false); 

... 

someClassMock.Stub(sc => sc.HandleError()).WhenCalled(invocation => mre.Set()); 

... 

testedClass.TestedMethod(); // call your real code using someClassMock 

... 

mre.WaitOne(timeoutErrorTime); 

someClassMock.AssertWasCalled(sc => sc.HandleError()); 

修改的例子,因爲你需要。不要忘記ManualResetEvent是diposable。我使用測試初始化​​和測試完整的方法來實例化和處理它。

0

根據您的測試需求,您可能需要引入一個時間界面。如果您不能重寫時間消費者,這可能沒有幫助。

using NUnit.Framework; 
using Rhino.Mocks; 
using System; 
using System.Threading.Tasks; 

namespace StackOverflow_namespace 
{ 
    public interface IDateTime 
    { 
     DateTime Now(); 
    } 

    public class DateTimeAdapter : IDateTime 
    { 
     public DateTime Now() { return DateTime.Now; } 
    } 

    public class Waiter 
    { 
     public static void WaitAnHour(IDateTime time) 
     { 
      //Incredibly wasteful - just to illustrate the point 
      DateTime start = time.Now(); 
      DateTime end = start + TimeSpan.FromHours(1); 
      while (end < time.Now()) ; 
     } 
    } 

    [TestFixture] 
    class StackOverflow 
    { 
     [Test] 
     public void TestingTimeout() 
     { 
      DateTime testtime = DateTime.Now; 
      var time = MockRepository.GenerateMock<IDateTime>(); 
      time.Stub(x => x.Now()).Do(new Func<DateTime>(() => { return testtime; })); 
      var task = Task.Run(() => Waiter.WaitAnHour(time)); 
      Assert.IsFalse(task.IsCompleted, "Just Started"); 
      testtime = testtime.AddMinutes(60); 
      task.Wait(); 
      Assert.IsTrue(task.IsCompleted, "60 Minutes Later"); 
     } 

    } 
} 
相關問題