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