问题
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....
回答1:
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.
回答2:
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());
}
回答3:
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);
}
回答4:
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);
}
来源:https://stackoverflow.com/questions/123394/rhino-mocks-re-assign-a-new-result-for-a-method-on-a-stub