3

我知道我可以这样做:

IDateTimeFactory dtf = MockRepository.GenerateStub<IDateTimeFactory>();
dtf.Now = new DateTime();
DoStuff(dtf); // dtf.Now can be called arbitrary number of times, will always return the same value
dtf.Now = new DateTime()+new TimeSpan(0,1,0);  // 1 minute later
DoStuff(dtf); //ditto from above

如果IDateTimeFactory.Now不是一个属性,而是一个方法IDateTimeFactory.GetNow(),我该怎么做呢?

根据下面 Judah 的建议,我重写了我的 SetDateTime 辅助方法,如下所示:

    private void SetDateTime(DateTime dt) {
        Expect.Call(_now_factory.GetNow()).Repeat.Any();
        LastCall.Do((Func<DateTime>)delegate() { return dt; });
    }

但它仍然会抛出“ICurrentDateTimeFactory.GetNow() 的结果;已经设置。” 错误。

再加上它仍然不能与存根一起工作......

4

4 回答 4

7

我知道这是一个老问题,但我想我会发布更新的 Rhino Mocks 版本。

根据之前使用 Do() 的答案,如果您在 Rhino Mocks 中使用 AAA(从 3.5+ 版本开始提供),则可以使用一种稍微清洁(IMO)的方式。

    [Test]
    public void TestDoStuff()
    {
        var now = DateTime.Now;
        var dtf = MockRepository.GenerateStub<IDateTimeFactory>();
        dtf
           .Stub(x => x.GetNow())
           .Return(default(DateTime)) //need to set a dummy return value
           .WhenCalled(x => x.ReturnValue = now); //close over the now variable

        DoStuff(dtf); // dtf.Now can be called arbitrary number of times, will always return the same value
        now = now + new TimeSpan(0, 1, 0); // 1 minute later
        DoStuff(dtf); //ditto from above
    }

    private void DoStuff(IDateTimeFactory dtf)
    {
        Console.WriteLine(dtf.GetNow());
    }
于 2011-02-05T00:29:08.740 回答
1

乔治,

使用您更新的代码,我得到了这个工作:

MockRepository mocks = new MockRepository();

[Test]
public void Test()
{
    IDateTimeFactory dtf = mocks.DynamicMock<IDateTimeFactory>();

    DateTime desiredNowTime = DateTime.Now;
    using (mocks.Record())
    {
        SetupResult.For(dtf.GetNow()).Do((Func<DateTime>)delegate { return desiredNowTime; });
    }
    using (mocks.Playback())
    {
        DoStuff(dtf); // Prints the current time    
        desiredNowTime += TimeSpan.FromMinutes(1);  // 1 minute later    
        DoStuff(dtf); // Prints the time 1 minute from now
    }
}

void DoStuff(IDateTimeFactory factory)
{
    DateTime time = factory.GetNow();
    Console.WriteLine(time);
}

FWIW,我不相信您可以使用存根来完成此操作;您需要改用模拟。

于 2008-09-23T21:54:55.517 回答
0

您可以使用 Expect.Call 来完成此操作。这是使用记录/播放模型的示例:

using (mocks.Record())
{
   Expect.Call(s.GetSomething()).Return("ABC"); // 1st call will return ABC
   Expect.Call(s.GetSomething()).Return("XYZ"); // 2nd call will return XYZ
}
using (mocks.Playback())
{
   DoStuff(s);
   DoStuff(s);
}
于 2008-09-23T20:07:19.927 回答
0

好的,所以我的第一个答案对您不起作用,因为 GetSomething 可能会被多次调用,而您不知道多少次。

您在这里遇到了一些复杂的场景——未知数量的方法调用,但在调用 DoSomething 后会产生不同的结果——我建议您分解单元测试以使其更简单,否则您必须为您的单元进行单元测试测试。:-)

如果做不到这一点,您可以通过以下方式完成您正在尝试做的事情:

bool shouldReturnABC = true;
using (mocks.Record())
{
   Expect.Call(s.GetSomething()).Repeat.Any();

   LastCall.Do((Func<string>)delegate()
   {
      return shouldReturnABC ? "ABC" : "XYZ";
   }
}
using (mocks.Playback())
{
   DoStuff(s);
   shouldReturnABC = false;
   DoStuff(s);
}
于 2008-09-23T20:43:25.877 回答