有没有人知道是否可以使用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));
}
答案 0 :(得分: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是diposable。我使用test initialize并测试完整的方法来实例化和处理它。
答案 1 :(得分: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");
}
}
}