13

我有一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用法,但我想了解这是否可能。

4

5 回答 5

12

如果方法标记为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 调用底层原始方法的第三行(单独的)。

于 2013-03-05T14:41:27.183 回答
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.

于 2009-11-25T15:42:59.240 回答
4

我刚刚发现可以通过在这两种方法上不使用 virtual 来实现这一点——它可以保护方法在生成存根时不被覆盖。

public class TimeMachine
{
    public virtual DateTime GetCurrentDateTime(){ return DateTime.Now; };
    public DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
    public TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}

现在测试通过了。

于 2009-11-25T15:49:20.667 回答
1

存根只是为方法和属性调用提供固定答案,它对 TimeMachine 的实际实现一无所知。恐怕您必须为 3 种方法中的每一种(或您要测试的特定方法)设置结果。

于 2009-11-25T15:40:57.080 回答
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());
}
于 2009-11-25T19:43:25.747 回答