How to test logic which is dependent on current date

前端 未结 8 1439
名媛妹妹
名媛妹妹 2020-12-20 16:52

I have this method which is dependent on current date. It checks if today is Sun, Mon, Tue or Wed, then it gives 5 days of lead time for arrival of shipped items. If its Thu

相关标签:
8条回答
  • 2020-12-20 16:54

    You need to pass the current date in as a parameter:

    private DateTime GetEstimatedArrivalDate(DateTime currentDate)
    {
        DateTime estimatedDate; 
        if (currentDate.DayOfWeek >= DayOfWeek.Thursday)
        {
            estimatedDate = currentDate.AddDays(6);
        }
        else
        {
            estimatedDate = currentDate.AddDays(5);
        }
        return estimatedDate; 
    }
    

    In real code you call it like this:

    DateTime estimatedDate = GetEstimatedArrivalDate(DateTime.Now.Date);
    

    Then you can test it as follows:

    DateTime actual = GetEstimatedArrivalDate(new DateTime(2010, 2, 10));
    DateTime expected = ...;
    // etc...
    

    Note that this also fixes a potential bug in your program where the date changes between consecutive calls to DateTime.Now.

    0 讨论(0)
  • 2020-12-20 17:00

    Make your class take an IClock parameter (via constructor or property)

    interface IClock
    {
        DateTime Now { get; }
    }
    

    You can then use a fake implementation for testing

    class FakeClock : IClock
    {
        DateTime Now { get; set }
    }
    

    and a real implementation the rest of the time.

    class SystemClock : IClock
    {
        DateTime Now { get { return DateTime.Now; } }
    }
    
    0 讨论(0)
  • 2020-12-20 17:05

    You could pass in a delegate that returns DateTime.Now during normal execution, and then in your test pass in another delegate that returns a fixed date, and assert your result based on that.

    0 讨论(0)
  • 2020-12-20 17:08

    I'll give the controversial answer, don't test it.

    The logic is trivial and it has zero dependencies, i believe in good code coverage but not when it increases complexity for no real gain.

    0 讨论(0)
  • 2020-12-20 17:14

    I would suggest doing this as Mark suggests, but with the addition of a overloaded call for production use that takes no parameter and uses DateTime.Now

    private DateTime GetEstimatedArrivalDate()
    {
        return GetEstimatedArrivalDate(DateTime.Now);
    }
    
    private DateTime GetEstimatedArrivalDate(DateTime currentDate)
    {
        DateTime estimatedDate; 
        if (currentDate.DayOfWeek >= DayOfWeek.Thursday)
        {
            estimatedDate = currentDate.AddDays(6);
        }
        else
        {
            estimatedDate = currentDate.AddDays(5);
        }
        return estimatedDate; 
    }
    
    0 讨论(0)
  • 2020-12-20 17:16

    Generally speaking, you'd want to abstract the method of obtaining the current date and time behind an interface, eg:

    public interface IDateTimeProvider
    {
        DateTime Now { get; }
    }
    

    The real service would be:

    public class DateTimeProvider: IDateTimeProvider
    {
        public DateTime Now
        {
            get
            {
                return DateTime.Now;
            }
        }
    }
    

    And a test service would be:

    public class TestDateTimeProvider: IDateTimeProvider
    {
        private DateTime timeToProvide;
        public TestDateTimeProvider(DateTime timeToProvide)
        {
            this.timeToProvide = timeToProvide;
        }
    
        public DateTime Now
        {
            get
            {
                return timeToProvide;
            }
        }
    }
    

    For services that require the current time, have them take an IDateTimeProvider as a dependency. For the real thing, pass a new DateTimeProvider(); when you're a component, pass in a new TestDateTimeProvider(timeToTestFor).

    0 讨论(0)
提交回复
热议问题