[英]C# Unit Testing - Thread.Sleep(x) - How to Mock the System Clock
我必須測試一個間隔后做一定工作量的方法。
while (running)
{
...
// Work
...
Thread.Sleep(Interval);
}
Interval作為參數傳遞給類,所以我可以傳入0或1,但我對如何模擬系統時鍾感興趣,如果不是這樣的話。
在我的測試中,我希望能夠通過TimeSpan Interval簡單地設置時間並讓線程喚醒。
我從來沒有為之前對執行線程起作用的代碼編寫測試,我確信有一些缺陷要避免 - 請隨意詳細說明你使用的方法。
謝謝!
如果您不希望測試線程實際休眠的事實,那么更直接的方法(也是可能的方法)就是擁有一個ISleepService。 然后你可以模擬它,然后不在你的測試中睡覺,但有一個實現確實會導致生產代碼中的Thread.Sleep。
ISleepService sleepService = Container.Resolve<ISleepService>();
..
while (running)
{
...
// Work
...
sleepService.Sleep(Interval);
}
使用Moq的示例:
public interface ISleepService
{
void Sleep(int interval);
}
[Test]
public void Test()
{
const int Interval = 1000;
Mock<ISleepService> sleepService = new Mock<ISleepService>();
sleepService.Setup(s => s.Sleep(It.IsAny<int>()));
_container.RegisterInstance(sleepService.Object);
SomeClass someClass = _container.Resolve<SomeClass>();
someClass.DoSomething(interval: Interval);
//Do some asserting.
//Optionally assert that sleep service was called
sleepService.Verify(s => s.Sleep(Interval));
}
private class SomeClass
{
private readonly ISleepService _sleepService;
public SomeClass(IUnityContainer container)
{
_sleepService = container.Resolve<ISleepService>();
}
public void DoSomething(int interval)
{
while (true)
{
_sleepService.Sleep(interval);
break;
}
}
}
更新
在設計\\維護說明中,如果更改“SomeClass”的構造函數是痛苦的,或者將依賴注入點添加到類的用戶,那么服務定位器類型模式可以在這里提供幫助,例如:
private class SomeClass
{
private readonly ISleepService _sleepService;
public SomeClass()
{
_sleepService = ServiceLocator.Container.Resolve<ISleepService>();
}
public void DoSomething(int interval)
{
while (true)
{
_sleepService.Sleep(interval);
break;
}
}
}
你無法真正模擬系統時鍾。
如果你需要能夠改變這樣的代碼的掛起行為,你需要重構它,這樣你就不會直接調用Thread.Sleep()
。
我會創建一個單例服務,它可以在測試時注入應用程序。 單例服務必須包括允許某些外部調用者(如單元測試)能夠取消睡眠操作的方法。
或者,您可以使用具有超時參數的Mutex
或WaitHandle
對象的WaitOne()
方法。 這樣你可以觸發互斥鎖取消“睡眠”或讓它超時:
public WaitHandle CancellableSleep = new WaitHandle(); // publicly available
// in your code under test use this instead of Thread.Sleep()...
while( running ) {
// .. work ..
CancellableSleep.WaitOne( Interval ); // suspends thread for Interval timeout
}
// external code can cancel the sleep by doing:
CancellableSleep.Set(); // trigger the handle...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.