I have a TimeMachine class which provides me current date/time values. The class looks like this:
public class TimeMachine
{
public virtual DateTime GetCurrentDateTime(){ return DateTime.Now; };
public virtual DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public virtual TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
I'd like to use TimeMachine stub in my tests in such way that I'd just stub the GetCurrentDateTime method and let the other 2 methods use the stubbed GetCurrentDateTime method so as I don't have to stub all the three methods. I tried to do write the test like this:
var time = MockRepository.GenerateStub<TimeMachine>();
time.Stub(x => x.GetCurrentDateTime())
.Return(new DateTime(2009, 11, 25, 12, 0, 0));
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
But the test fails. GetCurrentDate returns default(DateTime) instead of using GetCurrentDateTime stub internally.
Is there any approach I could use to achieve such behavior or is it just some basic conceptual feature of RhinoMocks I don't catch at the moment? I know I could just get a rid of those two GetDate/Time methods and inline the .Date/.TimeOfDay usage, but I'd like to understand whether this is possible at all.
If the method is marked as virtual, a Stub will not call the original method, even if you didn't Stub the method. You can force RhinoMocks to call the original method by doing:
var time = MockRepository.GenerateStub<TimeMachine>();
time.Stub(x => x.GetCurrentDateTime()).Return(new DateTime(2009, 11, 25, 12, 0, 0));
time.Stub(x => x.GetCurrentDate()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
It's the third (seperated) line that makes RhinoMocks call the underlying, original method.
Change your TimeMachine to an abstract class:
public abstract class TimeMachine
{
public abstract DateTime GetCurrentDateTime();
public DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
For production purposes, you can create a concrete implementation of TimeMachine like this:
public class SystemTimeMachine : TimeMachine
{
public override DateTime GetCurrentDateTime()
{
return DateTime.Now;
}
}
All classes consuming TimeMachine can now be injected with the abstraction, but in production you can wire up your object graph with SystemTimeMachine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With