1

我最近一直在尝试学习接口。

我看到了这段代码,无法理解为什么你不单独使用DateTime.Now它。我不确定为什么该界面有用,有人可以解释一下吗?这本书的作者试图解释,但我真的不明白如何按照他们所说的方式实现它:

程序员是否在抽象的海洋中迷失了自己?你可能会这么想,但实际上这很聪明。想象一下,您必须在一个类上运行一些测试,根据当前时间(或日期)给出不同的结果。这一点也不罕见。也许它是一个需要在给定日期获取汇率的金融应用程序。因此,请尝试测试代码库是否直接在方法中包含 DateTime.Now。使用 INowResolver,您可以注入您的现在并测试昨天、现在和明天

public interface INowResolver { DateTime GetNow(); } 

public class NowResolver : INowResolver { 
   public DateTime GetNow() {  
       return DateTime.Now;     
   } 
}

当我测试它时,如果我使用该NowResolver.GetNow方法或只是使用DateTime.Now.

测试:

        NowResolver now = new NowResolver();
        Console.WriteLine(now.GetNow());
        Console.WriteLine(DateTime.Now);
        System.Threading.Thread.Sleep(1000);
        Console.WriteLine(now.GetNow());
        Console.WriteLine(DateTime.Now);

输出:

07/02/2019 15:14:56
07/02/2019 15:14:56
07/02/2019 15:14:57
07/02/2019 15:14:57
4

4 回答 4

9

在编写单元测试时,每次运行测试时都必须以完全相同的方式执行测试,这一点很重要。

如果您的测试(或正在测试的代码)使用DateTime.Now(or DateTime.UtcNow),那么每次运行时您都会得到不同的测试结果(假设您正在测试包含 say 的属性DateTime)。

如果你抽象DateTime成一个接口,你可以让它在你的测试运行时,它总是在INowResolver.Now被调用时返回相同的时间。

示例: 在此测试中,时间始终为 2018 年 1 月 1 日。

public class MyTest
{
    public class TestNow : INowResolver
    {
       public DateTime Now {get;set;}
       public DateTime GetNow() => Now;
    }

    [Test]
    public void MyTest()
    {
       var resolver = new TestNow { Now = new DateTime(2018,1,1) }

       var testClass = new TestClass(resolver);

    }
}

实际上,如果我使用此方法的所有情况Now都是一个属性,就像它在 中一样DateTime.Now,而不是一个函数。

于 2019-02-07T15:20:45.653 回答
4

正如本书所指出的,这里的重点是测试。

假设您有逻辑需要在星期六做一些特别的事情。您想为此编写一个测试(很自然)。直接使用DateTime.Now您的测试只能在星期六运行。使用该界面,您可以拥有一个总是返回星期六日期的模拟,因此可以随时运行测试。

于 2019-02-07T15:20:31.590 回答
1

要添加上面的答案,它可以用来冻结时间:

在网络请求中,您希望冻结时间,以便所有修改的日期都对齐(即不是 +/- 几秒

意思是,您可以实现一个IDisposable覆盖,以便可以在这样的固定范围内操纵时间。

using (var o = new OverrideDateTimeProvider(DateTimeProvider.Now))
{
    // logic
    entity.Created = o.UtcNow;
    // other logic that can takes several seconds
    var otherEntity = CreateAsync();
    otherEntity.Created = o.UtcNow;
   // persistance logic
   uow.Commit();
}

有关更多信息,请参阅此存储库

于 2021-02-19T22:39:20.880 回答
0

实现将NowResolver使用DateTime.Now. 另一种实现可能会在GetNow上周六或昨天等返回。

该接口保证每个版本、每个实现都将提供一个GetNow方法。类本身决定了GetNow它的意义。

于 2019-02-07T15:22:58.283 回答