0

有谁知道是否可以使用 Rhino Mocks 来检查一个方法是否在给定的时间段内被调用?

这是我要为其编写单元测试的代码:

while (true)
    if (TimeoutErrorStopwatch.IsRunning && 
        TimeoutErrorStopwatch.ElapsedMilliseconds > timeoutErrorTime)
    {
        someClass.HandleError();
    }
    else
        Thread.Sleep(10);

我想编写一个单元测试,通过检查是否调用了 HandleError 方法来确保捕获错误。这个循环在它自己的后台线程上运行,所以我想知道是否有一种方法可以断言该方法是在一个约束条件下调用的,以继续检查并断言该方法在给定时间内被调用。大意是:

someClass.AssertWasCalled(s => s.HandleError()).Within(10);

我目前的解决方法是我简单地调用Thread.Sleep(10)然后使用AssertWasCalled,但我想知道 Rhino Mocks 是否支持这样的东西。

谢谢!

- - - 编辑 - - -

根据评论,我编写了一个扩展方法,检查该方法是否已被调用,直到达到给定的时间限制,在失败的调用之间休眠。我实际上已经模拟了计时器(在实际应用程序中,超时设置为 30 分钟,而在我的测试中,我设置了 100 毫秒或更短的模拟值)。我想我会发布我的扩展,以防有人偶然发现这篇文章。

public static void AssertWasCalledWithin<T>(this T stub, Action<T> action, long milliseconds)
    {
        var timer = Stopwatch.StartNew();
        var e = new Exception();
        while (timer.ElapsedMilliseconds <= milliseconds)
            try
            {
                stub.AssertWasCalled(action);
                return;
            }
            catch (ExpectationViolationException exc)
            {
                e = exc;
                Thread.Sleep(1);
            }

        throw new ExpectationViolationException(
            string.Format(
                "The following expectation was not met within the " +
                "given time limit of {0} milliseconds: {1}",
                milliseconds, e.Message));
    }
4

2 回答 2

2

我将 ManualResetEvent 与 WhenCalled 扩展方法结合使用来进行此类测试:

ManualResetEvent mre = new ManualResetEvent(false);

...

someClassMock.Stub(sc => sc.HandleError()).WhenCalled(invocation => mre.Set());

...

testedClass.TestedMethod(); // call your real code using someClassMock

...

mre.WaitOne(timeoutErrorTime);

someClassMock.AssertWasCalled(sc => sc.HandleError());

根据需要修改示例。不要忘记 ManualResetEvent 是一次性的。我使用测试初始化​​和测试完整方法来实例化和处理它。

于 2013-06-27T19:20:41.320 回答
0

根据您的测试需求,您可能需要引入时间接口。如果您不能重写时间消耗者,这可能无济于事。

using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Threading.Tasks;

namespace StackOverflow_namespace
{
    public interface IDateTime
    {
        DateTime Now();
    }

    public class DateTimeAdapter : IDateTime
    {
        public DateTime Now() { return DateTime.Now; }
    }

    public class Waiter
    {
        public static void WaitAnHour(IDateTime time)
        {
            //Incredibly wasteful - just to illustrate the point
            DateTime start = time.Now();
            DateTime end = start + TimeSpan.FromHours(1);
            while (end < time.Now()) ;
        }
    }

    [TestFixture]
    class StackOverflow
    {
        [Test]
        public void TestingTimeout()
        {
            DateTime testtime = DateTime.Now;
            var time = MockRepository.GenerateMock<IDateTime>();
            time.Stub(x => x.Now()).Do(new Func<DateTime>(() => { return testtime; }));
            var task = Task.Run(() => Waiter.WaitAnHour(time));
            Assert.IsFalse(task.IsCompleted, "Just Started");
            testtime = testtime.AddMinutes(60);
            task.Wait();
            Assert.IsTrue(task.IsCompleted, "60 Minutes Later");
        }

    }
}
于 2016-11-23T16:19:34.480 回答