c# - Rhino Mocks 使用存根函数的输入参数来创建返回值
问题描述
我有两个接口:
interface ITimeframe
{
DateTime beginTime {get;}
DateTime endTime {get;}
}
interface ITimeframeFactory
{
ITimeframe Create(Datetime beginTime, DateTime endTime);
}
我的测试对象使用 ITimeframeFactory 来创建多个 ITimeframe。为了测试我的 TestObject,我给它一个模拟的 TimeframeFactory。因为我的测试对象处理创建的时间范围,所以模拟的 TimeframeFactory 需要创建返回正确值的模拟时间范围。
StackOverflow:如何存根函数似乎暗示了方向:使用WhenCalled:
var mockRepository = new MockRepository();
ITimeframeFactory mockedTimeframeFactory = mockRepository.Stub<ITimeFrameFactory>();
// when the mocked TimeframeFactory is asked to Create a timeframe,
// let it return a new mockedTimeFrame that returns the proper values for BeginTime and EndTime
using (mockRepository.Record())
{
mockedTimeframeFactory.Stub( (factory) => factory.Create(
Arg<DateTime>.Is.Anything,
Arg<DateTime.Is.Anything))
.WhenCalled( (call) =>
{
DateTime beginTime = (DateTime)call.Arguments[0];
DateTime endTime = (DateTime)call.Arguments[1];
// mock a new ITimeframe;
// this ITimeframe should return beginTime and endtime:
ITimeframe createdTimeframe = mockRepository.Stub<ITimeframe>();
createdTimeframe.Stub((timeframe) => timeframe.BeginTime).Return(beginTime);
createdTimeframe.Stub((timeframe) => timeframe.EndTime).Return(endTime);
call.ReturnValue = createdTimeframe;
});
}
用法:
using (mockRepository.Playback())
{
DateTime beginTime = new DateTime(2020, 1, 1);
DateTime endTime = new DateTime(2019, 2, 2);
ITimeframe createdTimeframe = mockedFactory.Create(beginTime, endTime);
Assert.IsNotNull(createdTimeframe);
DateTime mockedBeginTime = createdTimeframe.BeginTime;
DateTime mockedEndTime = createdTimeframe.EndTime;
Assert.AreEqual(beginTime, mockedBeginTime);
Assert.AreEqual(endTime, mockedEndTime);
}
在 mockedFactory.Create(...) 我看到它WhenCalled
被处理了。在WhenCalled 期间,它具有正确的开始时间和结束时间。
call.ReturnValue
也有效,因为在调用 Create 之后createdTimeframe
不为空。
但是,当我想检查 createdTimeframe 的属性时,我得到一个异常:
System.InvalidOperationException: '上一个方法'ITimeframe.get_BeginTime();' 需要返回值或抛出异常。
似乎 createdTimeframe.Stub 的存根无效?
如何解决这个问题?
解决方案
解决方案比我想象的要容易:在回放期间,当创建模拟时间帧时,这个模拟时间帧仍处于记录状态。
我所要做的就是通过调用Replay()将其设置为重播状态。
这样我可以创建几个不同的时间范围,如下面的代码所示。
using (this.mockRepository.Playback())
{
List<ITimeframe> createdTimeframes = new List<ITimeframe>();
DateTime beginTime = new DateTime(2020, 1, 1);
DateTime endTime = new DateTime(2019, 2, 2);
for (int i = 0; i < 10; ++i)
{
Timeframe createdTimeframe = this.mockedFactory.Create(beginTime, endTime);
// This should be a new Timeframe, not returned before
Assert.IsNotNull(createdTimeframe);
Assert.IsFalse(createdTimeframes.Contains(createdTimeframe));
createdTimeframes.Add(createdTimeframe);
// before using the stubs of this timeframe set in in playback:
createdTimeframe.Replay();
DateTime mockedBeginTime = createdTimeframe.BeginTime;
DateTime mockedEndTime = createdTimeframe.EndTime;
Assert.AreEqual(beginTime, mockedBeginTime);
Assert.AreEqual(endTime, mockedEndTime);
// change beginTime and endTime to create a new timeframe
beginTime = beginTime.AddMonths(i);
endTime = endTime.AddMonths(-i);
}
}
推荐阅读
- javascript - 下一个使用 Express 的 js 动态 API 调用
- java - 缓存java方法
- syncfusion - Blazor 问题呈现从 Web Api 返回的数据
- eclipse - npm start 适用于 Eclipse,不适用于 Visual Studio 代码
- android - 如何在两个 Activity 之间传递参数,但一个必须只支持第一个
- java - 无法在 selenium 中逐行写入 excel 单列中的数据
- python - 使用 Psycopg2 时,Postgres 在几百秒后在查询期间关闭连接
- django - django.core.exceptions.FieldError:不支持查找 DateTimeField 的“季度”或不允许加入该字段
- ios - 当我退出视图控制器时,如何在不按停止按钮的情况下杀死 Countdowntimer?
- c++ - C++ 强制函数参数求值顺序