Rhino Mocks: переназначить новый результат для метода на заглушке

Я знаю, что я могу сделать это:

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 (), как мне сделать то же самое?

Согласно предложению Иуды ниже, я переписал свой вспомогательный метод SetDateTime следующим образом:

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

но он по-прежнему выдает "Результат для ICurrentDateTimeFactory.GetNow(); уже настроен". ошибки.

Плюс его все еще не собирается работать с заглушкой....

4 ответа

Решение

Джордж,

Используя ваш обновленный код, я получил это для работы:

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, я не верю, что вы можете сделать это с помощью заглушек; вам нужно использовать вместо этого макет.

Я знаю, что это старый вопрос, но думал, что выложу обновление для более свежих версий Rhino Mocks.

Основываясь на предыдущих ответах, в которых используется Do(), существует несколько более чистый (IMO) способ, если вы используете AAA в Rhino Mocks (доступно с версии 3.5+).

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

Итак, мой первый ответ не работает для вас, потому что 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);
}

Вы можете использовать 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);
}
Другие вопросы по тегам