使用模拟起订量在单元测试执行的延迟(Simulate a delay in execution in

2019-08-19 15:24发布

我试图测试如下:

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代码,单元测试的结果不是我想要完成的任务。

任何人都可以建议使用起订量框架来模拟在消息的“交付”延迟一个更好的/准确的方法。 我省略了一些“胶水”代码,仅包括相关部分。 让我知道如果事情我已经离开了阻止你能够理解这个问题。

Answer 1:

如果你想有一个起订量模拟眼睁睁地对什么也不做,而你可以使用一个回调:

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()的执行时间相应地变化。



Answer 2:

当你设置你的模拟你可以告诉线程在返回FUNC睡觉:

Mock<IMyService> myService = new Mock<IMyService>();

myService.Setup(x => x.GetResultDelayed()).Returns(() => {
    Thread.Sleep(100);
    return "result";
});


Answer 3:

我不能让起订量版的工作,所以我最终作出这样的:

一个小例子使用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();

    }

}


Answer 4:

我喜欢和投票塞鲁普的解决方案。 我的回答是转换用作图书馆自己的版本。

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;
    }
}


Answer 5:

我有一个类似的情况,但有一个异步方法。 什么工作对我来说是做到以下几点:

 mock_object.Setup(scheduler => scheduler.MakeJobAsync())
  .Returns(Task.Run(()=> { Thread.Sleep(50000); return Guid.NewGuid().ToString(); }));


文章来源: Simulate a delay in execution in Unit Test using Moq