23

I am looking for an alternative to Microsoft Fakes in .NET Core. I know it is no longer supported in .NET Core. I just do not understand why not, I think it was a good solution in certain situations.

My problem is that I want to mock DateTime.Now. Previously you could do this with the following code:

System.Fakes.ShimDateTime.NowGet = () => 
{ 
   return new DateTime(2000, 1, 1); 
};

It is described in the Microsoft documentation, see the link for more information: https://learn.microsoft.com/en-us/visualstudio/test/using-shims-to-isolate-your-application-from-other-assemblies-for-unit-testing?view=vs-2017

For now I solved it by creating a wrapper for DateTime, which looks like this:

/// <summary>
/// Used for getting DateTime.Now(), time is changeable for unit testing
/// </summary>
public static class SystemTime
{
   /// <summary> 
   /// Normally this is a pass-through to DateTime.Now, but it can be 
   /// overridden with SetDateTime( .. ) for testing or debugging.
   /// </summary>
   public static Func<DateTime> Now = () => DateTime.Now;

   /// <summary> 
   /// Set time to return when SystemTime.Now() is called.
   /// </summary>
   public static void SetDateTime(DateTime dateTimeNow)
   {
      Now = () =>  dateTimeNow;
   }

   /// <summary> 
   /// Resets SystemTime.Now() to return DateTime.Now.
   /// </summary>
   public static void ResetDateTime()
   {
       Now = () => DateTime.Now;
   }
}

I owe this solution to the next StackOverflow post: Unit Testing: DateTime.Now

But I am not satisfied with this solution yet, because I feel I have to adjust my implementation for my testing. I do not think this is desirable.

I hope someone can help me with this, thanks in advance for the effort.

Undeadparade
  • 1,512
  • 2
  • 14
  • 30
  • It is very good solution. You will need this mocking also in manual testing or event in production, when you will need have current time different than time which is set up in OS. – TcKs Sep 25 '18 at 11:48
  • You are actually improving the implementation by making the dependency on DateTime.Now explicit (which I assume was a hidden dependency) – Lennart Stoop Sep 25 '18 at 11:54
  • 5
    The proper way, for any system, platform, programming language, etc. is to actually remove the hard dependency on `DateTime.Now` (or the equivalent if this is another system, platform, etc.) so that you can inject it. Hidden dependencies are the scourge of testing because ... well ... they are *hidden*, ie. not visible to you, so they're just too darn easy to miss and overlook when you set up new test scenarios. For you to actually put it behind an abstraction that then has to be injected (which you should also do) makes this dependency visible, and thus easier to handle. – Lasse V. Karlsen Sep 25 '18 at 11:55
  • 1
    Rather than use a `static`, I would (like Lasse) generally implement this as a `DateTimeProvider : IDateTimeProvider`. Then your classes have an explicit dependency on `IDateTimeProvider`. This makes it crystal clear what classes have a dependency on `DateTime`, and thus need to be mocked. The downside of using `static`, from a unit testing standpoint, is that your tests then can't be parallelised (since there is only a single `static` value, so if different tests want to model different values they will trample on each other). – mjwills Sep 25 '18 at 12:50
  • 1
    It's on their roadmap. See https://developercommunity.visualstudio.com/idea/351467/support-microsoft-fakes-on-net-core.html. – Mike Lowery May 30 '19 at 22:40

3 Answers3

10

Pose works well for this.

using Pose;

Shim dateTimeShim = Shim.Replace(() => DateTime.Now).With(() => new DateTime(2004, 4, 4));

// This block executes immediately
PoseContext.Isolate(() =>
{
    // All code that executes within this block
    // is isolated and shimmed methods are replaced

    // Outputs "4/4/04 12:00:00 AM"
    Console.WriteLine(DateTime.Now);

}, dateTimeShim);
Chris Gessler
  • 22,727
  • 7
  • 57
  • 83
5

I am looking for an alternative to Microsoft Fakes in .NET Core. I know it is no longer supported in .NET Core. I just do not understand why not, I think it was a good solution in certain situations.

Since May 19th 2020 Microsoft Fakes supports .NET Core.

https://learn.microsoft.com/en-us/visualstudio/releases/2019/release-notes#16.6.0

Francesco B.
  • 2,729
  • 4
  • 25
  • 37
2

Thanks for all the comments, that certainly helped me. I have slightly modified my implementation;

The SystemTime class is now called DateTimeProvider and looks like this:

/// <summary>
/// Used for getting DateTime.Now(), time is changeable for unit testing
/// </summary>
public class DateTimeProvider : IDateTimeProvider
{
   /// <summary> 
   /// Normally this is a pass-through to DateTime.Now, but it can be 
   /// overridden with SetDateTime( .. ) for testing or debugging.
   /// </summary>
   private Func<DateTime> _now = () => DateTime.Now;
   public Func<DateTime> Now { get => _now; private set => _now = value; }

   /// <summary> 
   /// Set time to return when DateTimeProvider.Now() is called.
   /// </summary>
   public void SetDateTime(DateTime dateTimeNow)
   {
      Now = () =>  dateTimeNow;
   }

   /// <summary> 
   /// Resets DateTimeProvider.Now() to return DateTime.Now.
   /// </summary>
   public void ResetDateTime()
   {
       Now = () => DateTime.Now;
   }
}

I have chosen to make the setter private for Now(). As a result, a developer must explicitly use the method SetDateTime() to change the time. You can also choose to use a auto getter and setter property.

I also added an interface so that the class can be injected:

public interface IDateTimeProvider
{
    Func<DateTime> Now { get; }
    void SetDateTime(DateTime dateTimeNow);
    void ResetDateTime();
}

I hope that someone else will also benefit from this.

Undeadparade
  • 1,512
  • 2
  • 14
  • 30
  • 3
    Nice try, but this is not a replacement to what Fakes did. It would not affect any 3rd party lib calls working with time and requires every team member to learn and consistently use the replacement API (like that's gonna happen) I do miss my fakes, they just worked with no fuss :( – Imre Pühvel Dec 17 '18 at 10:03
  • There's an interface called `ISystemClock` which is meant for this purpose of mocking out the current datetime. – Matthew Apr 05 '19 at 20:26
  • 1
    @ImrePühvel - if you miss Fakes that much, check out the nuget package 'Pose'. – Chris Gessler May 05 '19 at 12:11
  • @ChrisGessler, I did. Welcome try, but last time I checked, it it did not handle all my cases and seemed not production-ready yet. Probably works for `DateTime.Now`, though. – Imre Pühvel May 07 '19 at 06:17
  • 2
    Pose also hasn't been updated since 6/2018 and I can't seem to get it to work with .NET Core 3.1 at all. I get InvalidProgramExceptions when I try to call the Isolate method. – metalhead Dec 13 '19 at 19:02