简体   繁体   中英

Moq to verify certain value not predicable

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?

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM