Reputation: 122062
I know I can do this:
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
What if instead of IDateTimeFactory.Now being a property it is a method IDateTimeFactory.GetNow(), how do I do the same thing?
As per Judah's suggestion below I have rewritten my SetDateTime helper method as follows:
private void SetDateTime(DateTime dt) {
Expect.Call(_now_factory.GetNow()).Repeat.Any();
LastCall.Do((Func<DateTime>)delegate() { return dt; });
}
but it still throws "The result for ICurrentDateTimeFactory.GetNow(); has already been setup." errors.
Plus its still not going to work with a stub....
Upvotes: 3
Views: 3372
Reputation: 10464
I know this is an old question, but thought I'd post an update for more recent Rhino Mocks versions.
Based on the previous answers which use Do(), there is a slightly cleaner (IMO) way available if you are using AAA in Rhino Mocks (available from version 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());
}
Upvotes: 7
Reputation: 60011
George,
Using your updated code, I got this to work:
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, I don't believe you can accomplish this using stubs; you need to use a mock instead.
Upvotes: 1
Reputation: 60011
Ok, so my first answer doesn't work for you because GetSomething may be called multiple times, and you don't know how many times.
You're getting into some complex scenario here -- unknown number of method invocations, yet with different results after DoSomething is called -- I recommend breaking up your unit test to be simpler, or you'll have to have unit tests for your unit tests. :-)
Failing that, here's how you can accomplish what you're trying to do:
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);
}
Upvotes: 0
Reputation: 60011
You can use Expect.Call to accomplish this. Here's an example using the record/playback model:
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);
}
Upvotes: 0