Syntax Error
Syntax Error

Reputation: 1640

Why not just use DateTime.Now?

I have been trying to learn about interfaces recently.

I saw this piece of code and can't wrap my head around why you wouldn't just use DateTime.Now on its own. I'm unsure why the interface is useful, can someone explain please? The author of the book tried to explain but I don't really understand how to implement it the way they are saying:

Has the programmer lost himself in a sea of abstraction? You might be tempted to think so, but actually this is pretty smart. Imagine you have to run some tests on a class that gives different results dependent on the current time (or date). That’s not uncommon at all; maybe it’s a financial application that needs to get the exchange rate at a given date. So try testing that if the codebase has DateTime.Now directly in the methods. With the INowResolver you can inject your now and test for yesterday, now, and tomorrow

public interface INowResolver { DateTime GetNow(); } 

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

When I tested it the result was the same if I used the NowResolver.GetNow method or just used DateTime.Now.

Test:

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

Output:

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

Upvotes: 1

Views: 2619

Answers (4)

Benzara Tahar
Benzara Tahar

Reputation: 2217

To add upon the answers above, it can be used to freeze time:

In a web request, you want to freeze time so that all your modified dates are aligned (i.e. not +/- by a few seconds

Meaning, you can implement an IDisposable Override so that time can be manipulated in a fixed scope like this.

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

see this repository for more information.

Upvotes: 1

Neil
Neil

Reputation: 11889

When you are writing unit tests, it is important that the tests execute in exactly the same way, every time you run them.

If your test (or code being tested) uses DateTime.Now (or DateTime.UtcNow), then every time it runs you will get a different test result (assuming you are testing the property that contains said DateTime).

If you abstract away DateTime into an interface, you can make it so that when your test runs, it always returns the same time when INowResolver.Now is called.

Example: In this test, the time will always be 1st Jan 2018.

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

    }
}

Actually, if all cases I've used this method, Now is a property, just like it is in DateTime.Now, not a function.

Upvotes: 11

Andy G
Andy G

Reputation: 19367

The NowResolver implementation will use DateTime.Now. Another implementation might have GetNow that returns last saturday, or yesterday, etc..

The interface guarantees that each version, each implementation, will provide a GetNow method. It is the class itself that determines what GetNow means to it.

Upvotes: 0

BradleyDotNET
BradleyDotNET

Reputation: 61349

The point here, as the book indicates, is tests.

Lets say you have logic that needs to do something special on Saturday. You want to write a test for this (quite naturally). Using DateTime.Now directly your test can only be run on Saturday. Using the interface you can have a mock that always returns a date that is on a Saturday, so the test can be run any time.

Upvotes: 4

Related Questions