为什么不只使用DateTime.Now?

时间:2019-02-07 15:17:36

标签: c# interface

我最近一直在尝试了解界面。

我看到了这段代码,无法理解为什么您不单单使用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 个答案:

答案 0 :(得分:8)

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

如果您的测试(或正在测试的代码)使用DateTime.Now(或DateTime.UtcNow),则每次运行时,您都会得到不同的测试结果(假设您正在测试包含上述{ {1}}。

如果您将DateTime提取到一个接口中,则可以使其变得如此,以便在运行测试时,它总是在调用DateTime的同一时间返回。

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

INowResolver.Now

实际上,如果在所有情况下我都使用此方法,则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中的属性一样,而不是函数。

答案 1 :(得分:4)

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

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

答案 2 :(得分: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();
}

有关详细信息,请参阅 this repository

答案 3 :(得分:0)

Private Sub StandRev() Dim VlookUp As Range Dim lastrev As Date With Worksheets("Tables") 'sets a look up range within the table "Contact" Set VlookUp = Contact.Parent.Range(Contact.ListColumns("SID").DataBodyRange, Contact.ListColumns("Last Review").DataBodyRange) lastrev = Application.WorksheetFunction.VlookUp(RevSID, VlookUp, 8,False) '*** problem here -- RevSID variable is assigned in previous sub ' no data is saved in variable, program ends sub If lastrev > AttempDate2 Then 'code that will replace lastrev with data in AttempDate2, AttempDate2 varaiable assigned in another sub End If End With End Sub 实现将使用NowResolver。另一个实现可能有DateTime.Now返回的是上个星期六或昨天等。

该接口保证每个版本,每个实现将提供一个GetNow方法。类本身决定GetNow对其的含义。