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


2

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

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(); уже настроен.» ошибки.

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

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

  0

Спасибо за вашу помощь Judah 23 сен. 082008-09-23 22:27:19

  0

Рад, что это работает для вас! FWIW, я отправил по электронной почте Айенде об этом сообщении. У него может быть лучший ответ для вас, чем я. 23 сен. 082008-09-23 22:29:27

+1

Джордж, Айенде посмотрел на эти ответы. Он сказал, что мы можем использовать закрытие и использовать SetupResult.For вместо Expect.Call (...). Repeat.Any(). В противном случае он не возражал против этих ответов. 24 сен. 082008-09-24 01:54:36

+1

Айенде также сказал: «Вы можете использовать BackToRecord для замены ожиданий от метода». То есть вы можете вызвать SetupResult.For несколько раз, как и предполагалось первоначально, вам просто нужно вызвать метод BackToRecord перед его вызовом. 24 сен. 082008-09-24 14:42:51


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

Да, но это применимо только в том случае, если вы вызываете окутанный метод один раз внутри DoStuff(), что если вы хотите, чтобы он возвращал этот результат всегда так же, как и с свойством? Вы можете использовать .Repeat(), но я не думаю, что вы можете переопределить это. 23 сен. 082008-09-23 20:10:23

  0

Плюс я не думаю, что это работает с заглушками 23 сен. 082008-09-23 20:12:45

  0

Джордж, ладно, это было непонятно с вашего поста. Я напишу новый ответ, как вы можете это сделать. 23 сен. 082008-09-23 20:29:29


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

Его не так сложно, я издеваюсь над DateTime.Now, поэтому у меня есть IDateTimeNowFactory с GetNow(); который я хочу вернуть с тем же значением, пока я не скажу, чтобы он продвигался вперед. Я не могу представить, что это слишком крайний случай, это то же самое, что и свойства заглушки, но с методами 23 сен. 082008-09-23 20:47:27

  0

Достаточно справедливо. Помог ли мой ответ решить вашу проблему? Я протестировал его здесь, и он, похоже, работал правильно. 23 сен. 082008-09-23 20:49:08

  0

Как ни странно, нет, все еще сообщая, что результат уже настроен, позвольте мне уточнить мой вопрос, чтобы он приблизился к моему фактическому коду. 23 сен. 082008-09-23 20:56:28

  0

Хорошо, Джордж, я отправил еще один ответ и подтвердил, что он работает. 23 сен. 082008-09-23 22:02:17


6

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

Основываясь на предыдущих ответах, которые используют Do(), при использовании (доступно с версии 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()); 
    }