What's a good way to overwrite DateTime.Now during testing?

后端 未结 11 1186
一个人的身影
一个人的身影 2020-11-28 02:52

I\'ve got some (C#) code that relies on today\'s date to correctly calculate things in the future. If I use today\'s date in the testing, I have to repeat the calculation in

相关标签:
11条回答
  • 2020-11-28 03:14

    Using Microsoft Fakes to create a shim is a really easy way to do this. Suppose I had the following class:

    public class MyClass
    {
        public string WhatsTheTime()
        {
            return DateTime.Now.ToString();
        }
    
    }
    

    In Visual Studio 2012 you can add a Fakes assembly to your test project by right clicking on the assembly you want to create Fakes/Shims for and selecting "Add Fakes Assembly"

    Adding Fakes Assembly

    Finally, Here is what the test class would look like:

    using System;
    using ConsoleApplication11;
    using Microsoft.QualityTools.Testing.Fakes;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace DateTimeTest
    {
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestWhatsTheTime()
        {
    
            using(ShimsContext.Create()){
    
                //Arrange
                System.Fakes.ShimDateTime.NowGet =
                () =>
                { return new DateTime(2010, 1, 1); };
    
                var myClass = new MyClass();
    
                //Act
                var timeString = myClass.WhatsTheTime();
    
                //Assert
                Assert.AreEqual("1/1/2010 12:00:00 AM",timeString);
    
            }
        }
    }
    }
    
    0 讨论(0)
  • 2020-11-28 03:20

    Another one using Microsoft Moles (Isolation framework for .NET).

    MDateTime.NowGet = () => new DateTime(2000, 1, 1);
    

    Moles allows to replace any .NET method with a delegate. Moles supports static or non-virtual methods. Moles relies on the profiler from Pex.

    0 讨论(0)
  • 2020-11-28 03:22

    You could inject the class (better: method/delegate) you use for DateTime.Now in the class being tested. Have DateTime.Now be a default value and only set it in testing to a dummy method that returns a constant value.

    EDIT: What Blair Conrad said (he has some code to look at). Except, I tend to prefer delegates for this, as they don't clutter up your class hierarchy with stuff like IClock...

    0 讨论(0)
  • 2020-11-28 03:23

    I think creating a separate clock class for something simple like getting the current date is a bit overkill.

    You can pass today's date as a parameter so you can input a different date in the test. This has the added benefit of making your code more flexible.

    0 讨论(0)
  • 2020-11-28 03:24

    Simple answer: ditch System.DateTime :) Instead, use NodaTime and it's testing library: NodaTime.Testing.

    Further reading:

    • Unit testing with Noda Time
    • Dependency Injection: Inject Your Dependencies, Period!
    0 讨论(0)
提交回复
热议问题