我试图测试如下:
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的作为测试框架。 每当我运行单元测试,我得到以下的输出:
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代码,单元测试的结果不是我想要完成的任务。
任何人都可以建议使用起订量框架来模拟在消息的“交付”延迟一个更好的/准确的方法。 我省略了一些“胶水”代码,仅包括相关部分。 让我知道如果事情我已经离开了阻止你能够理解这个问题。
如果你想有一个起订量模拟眼睁睁地对什么也不做,而你可以使用一个回调:
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()
的执行时间相应地变化。
当你设置你的模拟你可以告诉线程在返回FUNC睡觉:
Mock<IMyService> myService = new Mock<IMyService>();
myService.Setup(x => x.GetResultDelayed()).Returns(() => {
Thread.Sleep(100);
return "result";
});
我不能让起订量版的工作,所以我最终作出这样的:
一个小例子使用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();
}
}
我喜欢和投票塞鲁普的解决方案。 我的回答是转换用作图书馆自己的版本。
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
/// <summary>
/// support halting a workflow and waiting for a finish request
/// </summary>
public class MockWorker
{
private readonly DateTime? _end;
private volatile bool _shouldStop;
/// <summary>
/// Create a worker object
/// </summary>
/// <param name="timeoutInMilliseconds">How long before DoWork will timeout. default - Null will not timeout.</param>
public MockWorker(int? timeoutInMilliseconds = null)
{
if (timeoutInMilliseconds.HasValue)
_end = DateTime.Now.AddMilliseconds(timeoutInMilliseconds.Value);
}
/// <summary>
/// Instruct DoWork to complete
/// </summary>
public void RequestStop()
{
_shouldStop = true;
}
/// <summary>
/// Do work async will run until either timeoutInMilliseconds is exceeded or RequestStop is called.
/// </summary>
public async Task DoWorkAsync()
{
while (!_shouldStop)
{
await Task.Delay(100);
if (_end.HasValue && _end.Value < DateTime.Now)
throw new AssertFailedException("Timeout");
}
}
/// <summary>
/// Do work async will run until either timeoutInMilliseconds is exceeded or RequestStop is called.
/// </summary>
/// <typeparam name="T">Type of value to return</typeparam>
/// <param name="valueToReturn">The value to be returned</param>
/// <returns>valueToReturn</returns>
public async Task<T> DoWorkAsync<T>(T valueToReturn)
{
await DoWorkAsync();
return valueToReturn;
}
}
我有一个类似的情况,但有一个异步方法。 什么工作对我来说是做到以下几点:
mock_object.Setup(scheduler => scheduler.MakeJobAsync())
.Returns(Task.Run(()=> { Thread.Sleep(50000); return Guid.NewGuid().ToString(); }));