Simulate a delay in execution in Unit Test using Moq
Solution 1
If you want a Moq mock to just sit and do nothing for a while you can use a callback:
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);
I've tried that in LinqPad and if you adjust the Thread.Sleep()
the execution time varies accordingly.
Solution 2
When you setup your mock you can tell the thread to sleep in the return func:
Mock<IMyService> myService = new Mock<IMyService>();
myService.Setup(x => x.GetResultDelayed()).Returns(() => {
Thread.Sleep(100);
return "result";
});
Solution 3
If running asynchronous code, Moq has the ability to delay the response with the second parameter via a TimeSpan
mockFooService
.Setup(m => m.GetFooAsync())
.ReturnsAsync(new Foo(), TimeSpan.FromMilliseconds(500)); // Delay return for 500 milliseconds.
If you need to specify a different delay each time the method is called, you can use .SetupSequence
like
mockFooService
.SetupSequence(m => m.GetFooAsync())
.Returns(new Foo())
.Returns(Task.Run(async () =>
{
await Task.Delay(500) // Delay return for 500 milliseconds.
return new Foo();
})
Solution 4
I could not get Moq version to work, so I ended up making something like this:
a small example using 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();
}
}
Solution 5
I had a similiar situation, but with an Async method. What worked for me was to do the following:
mock_object.Setup(scheduler => scheduler.MakeJobAsync())
.Returns(Task.Run(()=> { Thread.Sleep(50000); return Guid.NewGuid().ToString(); }));
Julian Easterling
I develop primarily in C# now but during the past 30 years, I've used Perl, PHP, Python, VB, Java, JavaScript, FORTRAN, C, C++ (though I hate C++), and a little bit of COBOL. These days when not writing code in C#, I'll write code in Python and JavaScript. I develop mainly on the Windows platform but I like to program for Linux systems once in a while. For more information about me, you can check my web site at julianscorner.com
Updated on March 20, 2021Comments
-
Julian Easterling about 3 years
I'm trying to test the following:
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; }
with the following unit test:
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() just returns a string of characters and the "Delay Delivery" method is
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; }
I'm using Moq as the mocking framework and MSTest as the testing framework. Whenever I run the unit test, I get the following output:
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
Beyond the obvious "code smell" using the Thread.Sleep in the methods above, the result of the unit test is not what I'm trying to accomplish.
Can anyone suggest a better/accurate way to use the Moq framework to simulate a delay in "delivery" of the message. I've left out some of the "glue" code and only included the relevant parts. Let me know if something I've left out that prevents you from being able to understand the question.