C# Moq用于验证不可预测的特定值

C# Moq用于验证不可预测的特定值,c#,unit-testing,moq,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()

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

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);
    }
}
我需要编写一个单元测试代码,以确保何时调用
function()
底层
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);
    }
[TestMethod()]
公开考试
{
var mockother=new Mock();
var mainJob=新的mainJob(mockother.Object);
mainJob.function();
mockother.Verify(x=>x.DoAnotherJob(It.IsAny()),Times.Once);
}
为了确保使用任何日期时间调用该函数,我无法指定确切的值,因为
DateTime
的实际值是不可预测的


有什么想法吗?

当您想要验证与
DateTime有关的任何内容时,总是会遇到困难。现在,属性值很可能在调用之间发生变化。您所能做的最好的事情如下:

mockAnother.Verify(x => x.DoAnotherJob(It.Is<DateTime>(d > DateTime.Now.AddSeconds(-1))), Times.Once);
然后您将使用它来代替日期时间。现在直接使用

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);
}
[TestMethod()]
公开考试
{
var now=DateTime.now;
var mockother=new Mock();
var mockTimeProvider=new Mock();
mockTimeProvider.Setup(x=>x.Now).Returns(Now);
var mainJob=新的mainJob(mockother.Object,mockTimeProvider.Object);
mainJob.function();
mockother.Verify(x=>x.doatherjob(现在),Times.Once);
}

Roy Osherove在(第134页)中建议使用一个
SystemTime
类,该类提供
.Now
和一种测试方法来设置
.Now
返回的内容。从这里开始,就是要确保所有的东西都使用这个类。回答得好。我想我会把你的第一个建议作为我的方法,因为我总是认为仅仅为了处理
DateTime而引入一些东西太沉重了。现在,我打赌构建服务器的运行速度足够快,可以在x秒内执行测试用例。
[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);
}