Stub一个类的方法,让其他真正的方法使用这个stubbed方法

时间:2009-11-25 15:35:49

标签: c# mocking rhino-mocks stub

我有一个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用法,但我想了解这是否可行一点都不。

5 个答案:

答案 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());
}