使用DateTimeOffset对象的单元测试类的正确方法?

时间:2016-03-30 18:08:32

标签: c# unit-testing datetime testing nunit

我希望了解如何正确测试使用DateTimeOffset实例的代码的信息或示例。我知道测试必须是确定性的。

那么,如何将应用程序与DateTimeOffset类隔离开来呢?当然,我希望能够使用假的DateTimeOffset.Now等。

在我的测试中,我应该使用类似的东西:

var myDate = new DateTimeOffset(2016, 3, 29, 12, 20, 35, 93, TimeSpan.FromHours(-3));

或者我会使用像MyCustomDateTimeOffset这样的包装类吗? 我的代码中根本不应该使用DateTimeOffset而是使用包装器吗?

2 个答案:

答案 0 :(得分:7)

正如fundamentals theorem所说:

  

我们可以通过引入额外的间接层来解决任何问题。

您真的不需要包装器,只需要避免使用DateTimeOffset.Now / DateTimeOffset.UtcNow

以下几种方法可以解决这个问题:

  • 如果使用依赖注入,请编写一个公开IClock / Now属性的UtcNow接口。

    public interface IClock
    {
        DateTimeOffset Now { get; }
        DateTimeOffset UtcNow { get; }
    }
    
    internal class Clock : IClock
    {
        public DateTimeOffset Now => DateTimeOffset.Now;
        public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
    }
    

    在测试中,您只需按照自己的意愿模拟界面。

  • 如果你宁愿继续使用静态属性,写一个静态类型,假设Clock,并使用它。

    public static class Clock
    {
        internal static Func<DateTimeOffset> DateTimeOffsetProvider { get; set; }
            = () => DateTimeOffset.Now;
    
        public static DateTimeOffset Now => DateTimeOffsetProvider();
        public static DateTimeOffset UtcNow => DateTimeOffsetProvider().ToUniversalTime();
    }
    

    在测试中,您可以替换DateTimeOffsetProvider

    这是一个.NET 2版本:

    public static class Clock
    {
        internal delegate DateTimeOffset DateTimeOffsetProviderDelegate();
        internal static DateTimeOffsetProviderDelegate DateTimeOffsetProvider { get; set; }
    
        public static DateTimeOffset Now { get { return DateTimeOffsetProvider(); } }
        public static DateTimeOffset UtcNow { get { return DateTimeOffsetProvider().ToUniversalTime(); } }
    
        static Clock()
        {
            DateTimeOffsetProvider = delegate() { return DateTimeOffset.Now; };
        }
    }
    

答案 1 :(得分:1)

由于你不知道DateTimeOffSet.Now的值,所以你不能断言DateTimeOffSet.Now等于一个值。

你可能应该重构使用以下两种方法之一:

  • 依赖注入
  • 界面和包装

依赖注入(DI)

DI意味着不是让方法确定日期,而是将其传入。

这种方法。 。

public void DoSomething()
{
   var now = DateTimeOffSet.Now;
   // Do other stuff with the date
}

。 。 。会改变这个方法

public void DoSomething(DateTimeOffSet dtos)
{
   // Do other stuff with the date
}

接口和包装

你的另一个选择(虽然最后你也会使用DI)是创建一个接口和一个包装器。然后使用对象中的接口而不是具体的DateTimeOffSet,这样您就可以使用MOQ或其他测试库来设置接口。查看SystemWrapper(https://github.com/jozefizso/SystemWrapper)项目以获取示例。