Moq验证某些值不可预测

时间:2015-01-21 14:18:56

标签: c# unit-testing moq

为了便于解释,我有以下代码

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

我需要编写一个单元测试代码,以确保在调用FunctionA()时调用基础IAnother.DoAnotherJob()以使用当前日期时间。

我可以编写测试代码

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

确保使用任何日期时间调用函数,但我无法指定确切的值,因为DateTime的实际值是不可预测的。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

当您想要验证有关DateTime.Now的任何内容时,您总是会感到困惑,因为属性值很可能会在调用之间发生变化。你能做的最好就是这样:

mockAnother.Verify(x => x.DoAnotherJob(It.Is<DateTime>(d > DateTime.Now.AddSeconds(-1))), Times.Once);

另一种方法是引入另一个类和抽象,用于解析DateTime

public interface ITimeProvider
{
    DateTime Now { get; }
}

public class TimeProvider : ITimeProvider
{
    DateTime Now { get { return DateTime.Now ; } }
}

然后您将直接使用而不是DateTime.Now

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

然后,您的单元测试变为:

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