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

モッキング フレームワークとして Moq を使用し、テスト フレームワークとして 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 を使用した明らかな "コードの匂い" を超えて、単体テストの結果は私が達成しようとしているものではありません。

Moqフレームワークを使用してメッセージの「配信」の遅延をシミュレートするためのより良い/正確な方法を誰でも提案できますか? 「グルー」コードの一部を省略し、関連する部分のみを含めました。質問を理解するのを妨げる何かが私が省略した場合はお知らせください。

4

6 に答える 6

48

Moq モックをただ座ってしばらく何もしないようにしたい場合は、コールバックを使用できます。

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()。実行時間を調整すると、それに応じて異なります。

于 2013-04-05T10:20:57.983 に答える
16

モックをセットアップするとき、スレッドに戻り関数でスリープするように指示できます。

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

myService.Setup(x => x.GetResultDelayed()).Returns(() => {
    Thread.Sleep(100);
    return "result";
});
于 2016-10-11T03:06:15.070 に答える
2

Moq バージョンを動作させることができなかったので、最終的に次のようなものを作成しました。

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();

    }

}
于 2016-06-03T16:35:44.970 に答える