.NET Core中有没有替代Microsoft Fakes的工具?

24

我正在寻找一个.NET Core中替代Microsoft Fakes的方案。我知道它在.NET Core中已不再受支持。我只是不明白为什么,我认为在某些情况下它是一个很好的解决方案。

我的问题是我想mock DateTime.Now。以前你可以使用以下代码来实现:

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

该技术在Microsoft文档中有描述,详细信息请参见以下链接:https://learn.microsoft.com/en-us/visualstudio/test/using-shims-to-isolate-your-application-from-other-assemblies-for-unit-testing?view=vs-2017

目前,我通过创建一个DateTime的包装器来解决这个问题,如下所示:

/// <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;
   }
}

我要感谢下面这篇StackOverflow的帖子提供的解决方案:Unit Testing: DateTime.Now

但我对这个解决方案还不满意,因为我觉得我必须根据我的测试来调整实现。我认为这是不可取的。

希望有人能帮助我,非常感谢您的努力。


1
这是一个非常好的解决方案。无论在手动测试中还是生产环境中,您都需要这种嘲弄(mocking),因为您可能需要当前时间与操作系统设置的时间不同。 - TcKs
1
你实际上通过使对 DateTime.Now 的依赖显式化(我假设这是一个隐藏的依赖)来改进了实现。 - Lennart Stoop
5
任何系统、平台、编程语言等的正确方式都是实际上移除对 DateTime.Now(或者如果是另一个系统、平台等则是等价的)的硬依赖,以便您可以注入它。隐藏依赖关系是测试的祸根,因为...嗯...它们是隐藏的,即对您不可见,因此在设置新的测试场景时很容易被忽略。将其放在需要注入的抽象后面(您也应该这样做)使得此依赖关系变得可见,从而更容易处理。 - Lasse V. Karlsen
1
与其使用 static,我通常会像 Lasse 一样将其实现为 DateTimeProvider : IDateTimeProvider。然后你的类就会显式地依赖于 IDateTimeProvider。这使得哪些类依赖于 DateTime 变得非常清晰,因此需要进行模拟。从单元测试的角度来看,使用 static 的缺点是你的测试无法并行化(因为只有一个 static 值,所以如果不同的测试想要模拟不同的值,它们将互相干扰)。 - mjwills
1
它在他们的路线图上。请查看 https://developercommunity.visualstudio.com/idea/351467/support-microsoft-fakes-on-net-core.html。 - Mike Lowery
3个回答

10

姿势在这方面表现良好。

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

1
每当调用异步方法时,它似乎总是会崩溃。https://github.com/tonerdo/pose/issues/25 - Brian Colavito

5

6
仅限于Visual Studio企业版用户使用。 - Antoine L
我现在已经看到了,是的。 - Francesco B.
它确实可以...但是在dotnet测试中不起作用,因为那是开源的。 - Mary Ellen Bench

2
感谢所有的评论,这确实对我有所帮助。我稍微修改了我的实现;
SystemTime类现在被称为DateTimeProvider,看起来像这样:
/// <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;
   }
}

我选择将Now()的setter设为私有。因此,开发人员必须显式使用SetDateTime()方法来更改时间。您还可以选择使用自动getter和setter属性。

我还添加了一个接口,以便可以注入该类:

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

我希望还有其他人也能从中受益。


3
尝试不错,但这并不能替代Fakes所做的。它不会影响任何使用时间的第三方库调用,并且需要每个团队成员学习并始终使用替代API(就像那样会发生一样)。我想念我的Fakes,它们只是无需费心地工作 :) - Imre Pühvel
有一个名为 ISystemClock 的接口,旨在模拟当前日期和时间。 - Matthew
1
@ImrePühvel - 如果你非常想念 Fakes,可以看看 nuget 包 'Pose'。 - Chris Gessler
@ChrisGessler,我试过了。欢迎尝试,但上次我检查时,它没有处理完所有我的情况,似乎还没有准备好投入生产。不过对于DateTime.Now可能有效。 - Imre Pühvel
2
Pose自2018年6月以来也没有更新,我似乎无法将其与.NET Core 3.1结合使用。当我尝试调用Isolate方法时,会出现InvalidProgramExceptions。 - metalhead

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接