0

In my Unit test file using Nunit, I am attempting to write test cases so as to test for all of the if/else branches. Is there a way to inject a specific DateTime.Now inside this method while calling it in the unit test?
The method takes Opening/Closing times for a restaurant.

public void LunchDinnerBummer(string openingTime, string closingTime)
{
    //Based on the current time, alerts the user
    //if it is lunch/dinner time or outside of 
    //business hours
    var openTime = DateTime.Parse(openingTime);
    var closeTime = DateTime.Parse(closingTime);

    //End of lunch time
    var lunchTime = DateTime.Parse("3:00 PM");

    //For lunch time
    if (openTime < DateTime.Now && DateTime.Now < lunchTime)
        Console.WriteLine("It is time to go to Ted’s for lunch!");

    //For dinner time
    else if (DateTime.Now > lunchTime && DateTime.Now < closeTime)
        Console.WriteLine("It is time to go to Ted’s for dinner!");

    //If outside of business hour before Opening Time for today
    else if (DateTime.Now < openTime)
    {
        TimeSpan span = openTime.Subtract(DateTime.Now);
        Console.WriteLine("Bummer, Ted’s is closed");
        Console.WriteLine("Ted’s will open in: " + span.Hours + " hour " + " and " + span.Minutes + " minutes ");
    }
    //If outside of business hours past closing time for today
    //Calculate for the hours and minutes left till opening time for next day
    else
    {
        var openTimeNextDay = openTime.AddDays(1);
        TimeSpan span = openTimeNextDay.Subtract(DateTime.Now);
        Console.WriteLine("Bummer, Ted’s is closed");
        Console.WriteLine("Ted’s will open in: " + span.Hours + " hour " + " and " + span.Minutes + " minutes ");
    }
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
RSSregex
  • 179
  • 7
  • Possible duplicate of [Unit Testing: DateTime.Now](https://stackoverflow.com/questions/2425721/unit-testing-datetime-now) – vladimir May 29 '19 at 05:41
  • 1
    The cited question is more general, i.e. how to test with DateTime.Now. This one is a fairly specific example with several possible specific answers. – Charlie May 29 '19 at 07:14

1 Answers1

2

One way (IMO the best) is to simply pass the current time as an argument.

public void LunchDinnerBummer(string openingTime, string closingTime, DateTime now)
...

Then your tests can use all sorts of different times, while your production code can pass DateTime.Now.

Going beyond the question as asked, I would guess that LunchDinnerBummer may be a method of some class that represents a restaurant. If that's the case, I would initialize open and close times in the constructor, simplifying LunchDinnerBummer to a single argument.

More stuff you didn't ask :-) ... Why use string as an argument rather than DateTime?

Charlie
  • 12,928
  • 1
  • 27
  • 31
  • The selenium web driver captures the Open and Closed times as a string/text . Those values are then passed to LunchDinnerBummer(). Yes, I though about changing the signature which would make it straight forward. – RSSregex May 29 '19 at 08:32
  • I think I'd go one further than this and inject in some interface `IClock` that provides a method `DateTime TimeNow()`, so then in your unit test you can mock the value that you need the clock to return, rather than expose another parameter to the method that isn't really needed. – LordWilmore May 29 '19 at 16:34
  • 1
    @LordWilmore Yes, I'm pretty sure he would be driven to that eventually. I generally have gotten the habit of keeping those things in my head until I'm really sure exactly what the interface will look like, but doing it now and changing later wouldn't be bad either. – Charlie May 30 '19 at 09:04