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