我有一个TimeMachine
类,它提供了当前的日期/时间值。该课程如下:
public class TimeMachine
{
public virtual DateTime GetCurrentDateTime(){ return DateTime.Now; };
public virtual DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public virtual TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
我想在我的测试中使用TimeMachine
存根,以便我只是存根GetCurrentDateTime
方法,让其他两种方法使用存根GetCurrentDateTime
方法因为我不必将所有这三种方法都存根。我试着像这样编写测试:
var time = MockRepository.GenerateStub<TimeMachine>();
time.Stub(x => x.GetCurrentDateTime())
.Return(new DateTime(2009, 11, 25, 12, 0, 0));
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
但测试失败了。 GetCurrentDate
返回default(DateTime)
,而不是在内部使用GetCurrentDateTime
存根。
我是否有任何方法可以用来实现这种行为,还是只是RhinoMocks的一些基本概念特征,我现在还没有抓住?我知道我可以摆脱这两种GetDate
/ Time
方法并内联.Date
/ .TimeOfDay
用法,但我想了解这是否可行一点都不。
答案 0 :(得分:11)
如果方法被标记为virtual
,即使您没有使用Stub方法,Stub也不会调用原始方法。您可以通过执行以下操作强制RhinoMocks调用原始方法:
var time = MockRepository.GenerateStub<TimeMachine>();
time.Stub(x => x.GetCurrentDateTime()).Return(new DateTime(2009, 11, 25, 12, 0, 0));
time.Stub(x => x.GetCurrentDate()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
这是使RhinoMocks调用底层原始方法的第三条(分离的)线。
答案 1 :(得分:9)
将您的TimeMachine
更改为抽象类:
public abstract class TimeMachine
{
public abstract DateTime GetCurrentDateTime();
public DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
出于生产目的,您可以像这样创建TimeMachine
的具体实现:
public class SystemTimeMachine : TimeMachine
{
public override DateTime GetCurrentDateTime()
{
return DateTime.Now;
}
}
现在,所有使用TimeMachine
的类都可以使用抽象注入,但在生产中,您可以使用SystemTimeMachine
连接对象图。
答案 2 :(得分:4)
我刚刚发现可以通过在这两种方法上不使用虚拟来实现这一点 - 它可以保护方法在生成存根时不被覆盖。
public class TimeMachine
{
public virtual DateTime GetCurrentDateTime(){ return DateTime.Now; };
public DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
现在测试通过了。
答案 3 :(得分:1)
存根只是提供方法和属性调用的固定答案,它对TimeMachine的实际实现一无所知。我担心你必须为3种方法中的每种方法(或者你想要测试的特定方法)设置结果。
答案 4 :(得分:1)
我不确定您使用的是哪个版本的Rhino.Mocks,但我要做的是只将GetCurrentDateTime()方法设为虚拟(如之前提到的海报),然后使用PartialMock()创建模拟对象。有很多方法可以设置,但以下内容应该有效:
var mocks = new MockRepository();
var time = mocks.PartialMock<TimeMachine>();
using (mocks.Record())
{
Expect.Call(time.GetCurrentDateTime()).Return(new DateTime(2009, 11, 25, 12, 0, 0));
}
using (mocks.Playback())
{
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
}