我有一些单元测试,期望“当前时间”与DateTime不同。显然,我不想改变电脑的时间。

实现这一目标的最佳策略是什么?


当前回答

在使用ITimeProvider时,我们被迫将它作为一个特殊的共享项目,必须从其他项目中引用它。但这使得依赖关系的控制变得复杂。

我们在。net框架中搜索ITimeProvider。我们搜索了NuGet包,发现了一个不能使用DateTimeOffset的包。

所以我们提出了自己的解决方案,它只依赖于标准库的类型。我们正在使用Func<DateTimeOffset>的实例。

如何使用

public class ThingThatNeedsTimeProvider
{
    private readonly Func<DateTimeOffset> now;
    private int nextId;

    public ThingThatNeedsTimeProvider(Func<DateTimeOffset> now)
    {
        this.now = now;
        this.nextId = 1;
    }

    public (int Id, DateTimeOffset CreatedAt) MakeIllustratingTuple()
    {
        return (nextId++, now());
    }
}

如何注册

自发法克

builder.RegisterInstance<Func<DateTimeOffset>>(() => DateTimeOffset.Now);

(未来的编辑请在这里附上你的案例)。

如何进行单元测试

public void MakeIllustratingTuple_WhenCalled_FillsCreatedAt()
{
    DateTimeOffset expected = CreateRandomDateTimeOffset();
    DateTimeOffset StubNow() => expected;
    var thing = new ThingThatNeedsTimeProvider(StubNow);

    var (_, actual) = thing.MakeIllustratingTuple();

    Assert.AreEqual(expected, actual);
}

其他回答

下面的代码为我工作:

  bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Year == DateTime.Now.Year)));
            bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Month == DateTime.Now.Month)));
            bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Day == DateTime.Now.Day)));

为系统添加一个假程序集(右键单击System reference=>添加假程序集)。

并在测试方法中写入:

using (ShimsContext.Create())
{
   System.Fakes.ShimDateTime.NowGet = () => new DateTime(2014, 3, 10);
   MethodThatUsesDateTimeNow();
}

也许不太专业,但更简单的解决方案可以在消费者方法中创建一个DateTime参数。例如,不使用像SampleMethod这样的make方法,而是使用带参数的make SampleMethod1。SampleMethod1的测试更简单

public void SampleMethod()
    {
        DateTime anotherDateTime = DateTime.Today.AddDays(-10);
        if ((DateTime.Now-anotherDateTime).TotalDays>10)
        {

        }
    }
    public void SampleMethod1(DateTime dateTimeNow)
    {
        DateTime anotherDateTime = DateTime.Today.AddDays(-10);
        if ((dateTimeNow - anotherDateTime).TotalDays > 10)
        {

        }

    }

在使用ITimeProvider时,我们被迫将它作为一个特殊的共享项目,必须从其他项目中引用它。但这使得依赖关系的控制变得复杂。

我们在。net框架中搜索ITimeProvider。我们搜索了NuGet包,发现了一个不能使用DateTimeOffset的包。

所以我们提出了自己的解决方案,它只依赖于标准库的类型。我们正在使用Func<DateTimeOffset>的实例。

如何使用

public class ThingThatNeedsTimeProvider
{
    private readonly Func<DateTimeOffset> now;
    private int nextId;

    public ThingThatNeedsTimeProvider(Func<DateTimeOffset> now)
    {
        this.now = now;
        this.nextId = 1;
    }

    public (int Id, DateTimeOffset CreatedAt) MakeIllustratingTuple()
    {
        return (nextId++, now());
    }
}

如何注册

自发法克

builder.RegisterInstance<Func<DateTimeOffset>>(() => DateTimeOffset.Now);

(未来的编辑请在这里附上你的案例)。

如何进行单元测试

public void MakeIllustratingTuple_WhenCalled_FillsCreatedAt()
{
    DateTimeOffset expected = CreateRandomDateTimeOffset();
    DateTimeOffset StubNow() => expected;
    var thing = new ThingThatNeedsTimeProvider(StubNow);

    var (_, actual) = thing.MakeIllustratingTuple();

    Assert.AreEqual(expected, actual);
}

模拟对象。

一个模拟DateTime,返回适合您的测试的Now。