Reputation: 5162
To make it easy to explain, I have following codes
public interface IAnother
{
void DoAnotherJob(DateTime date);
}
public class MainJob
{
private IAnother another;
public MainJob(IAnother another)
{
this.another = another;
}
public void FunctionA()
{
this.FunctionB(DateTime.Now);
}
public void FunctionB(DateTime date)
{
this.another.DoAnotherJob(date);
}
}
I need to write a unit test code to make sure when FunctionA()
is called the underlying IAnother.DoAnotherJob()
is called to use the current date time.
I can write the testing code
[TestMethod()]
public void FunctionATest()
{
var mockAnother = new Mock<IAnother>();
var mainJob = new MainJob(mockAnother.Object);
mainJob.FunctionA();
mockAnother.Verify(x => x.DoAnotherJob(It.IsAny<DateTime>()), Times.Once);
}
to make sure the function is called with any date time, but I have no way to specify the exact value since the real value of DateTime
is not predictable.
Any ideas?
Upvotes: 2
Views: 1170
Reputation: 16393
You are always going to struggle when you want to verify anything regarding DateTime.Now
as the property value will most likely change between calls. The best you can do is something like this:
mockAnother.Verify(x => x.DoAnotherJob(It.Is<DateTime>(d > DateTime.Now.AddSeconds(-1))), Times.Once);
The alternative is to introduce another class and abstraction which you use to resolve the DateTime
:
public interface ITimeProvider
{
DateTime Now { get; }
}
public class TimeProvider : ITimeProvider
{
DateTime Now { get { return DateTime.Now ; } }
}
Which you would then use instead of DateTime.Now
directly:
public class MainJob
{
private IAnother another;
private ITimeProvider timeProvider;
public MainJob(IAnother another, ITimeProvider timeProvider)
{
this.another = another;
this.timeProvider = timeProvider;
}
public void FunctionA()
{
this.FunctionB(this.timeProvider.Now);
}
public void FunctionB(DateTime date)
{
this.another.DoAnotherJob(date);
}
}
Then, your Unit Test becomes:
[TestMethod()]
public void FunctionATest()
{
var now = DateTime.Now;
var mockAnother = new Mock<IAnother>();
var mockTimeProvider = new Mock<ITimeProvider>();
mockTimeProvider.Setup(x => x.Now).Returns(now);
var mainJob = new MainJob(mockAnother.Object, mockTimeProvider.Object);
mainJob.FunctionA();
mockAnother.Verify(x => x.DoAnotherJob(now), Times.Once);
}
Upvotes: 4