Simulate a delay in execution in Unit Test using Moq

26,413

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(); }));
Share:
26,413
Julian Easterling
Author by

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, 2021

Comments

  • Julian Easterling
    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.