申请时间的设计模式?

时间:2013-10-15 10:52:20

标签: c# design-patterns testing

如果构建业务流程取决于 [1] 的时间的系统,则不能在代码中使用DateTime.Now或类似的代码,因为您必须处理测试例如,未来月末或年终场景。使用SSL证书时通常不能更改操作系统时间,因为对分布式系统执行更正是很复杂的。

一个选项是创建一个可以返回当前时间的所有系统都可访问的单件服务。在生产中,它可以返回DateTime.Now,并且在测试中它可以在月末场景中返回2月28日的游戏时间。

但有更好的方法吗?就像更加面向数据库的方法,因为它可以带来更好的性能?或者你会放入分布式缓存?这有一些众所周知的设计模式吗?

[1] 典型案例:保险系统,核心银行系统实施的业务流程......

5 个答案:

答案 0 :(得分:4)

解决此问题的一种方法是拥有clock interface

public interface IClock {
  DateTime Now { get; }
}

在整个代码中使用此界面,代替DateTime.Now。在生产中,您将使用其规范实现(或UTC变体):

public class SystemClock implements IClock {
  public DateTime Now { get { return DateTime.Now; } }
}

例如,您可以在需要SystemClock的所有类中使用IClock作为默认值,并允许通过构造函数或setter注入其他实现。

在测试中,您可以创建测试实现或使用模拟框架对其进行模拟。

答案 1 :(得分:2)

您可以考虑使用Microsoft Fakes来实现您所说的内容。

见这个稍微修改过的例子;

[TestMethod]
public void TestCurrentYear()
{
    int fixedYear = 2000;

    // Shims can be used only in a ShimsContext:
    using (ShimsContext.Create())
    {
        // Arrange:
        // Shim DateTime.Now to return a fixed date:
        System.Fakes.ShimDateTime.NowGet =  
        () =>
        { return new DateTime(fixedYear, 1, 1); };

        // Act:
        int year = DateTime.Now.Year;

        // Assert: 
        Assert.AreEqual(fixedYear, year);
    }
}

这里的优点是您不必更改任何使用DateTime使其可测试的代码。

答案 2 :(得分:2)

日期和时间是关键且复杂的(特别是由于时区和DST),我想您所提及的行业就是这种情况,您可能希望避免DateTime支持Noda time

Noda时间内置了单元测试功能,请参阅https://stackoverflow.com/a/14531915/360211

答案 3 :(得分:1)

对于单元测试,您应该能够存根,包括时间。一些模拟框架(例如Microsoft Shims)允许您覆盖DateTime.Now的行为。

对于集成/系统测试,我过去所做的是使用每个系统组件的配置设置,该配置设置指定要从真实DateTime使用的该组件的DateTime偏移量。这可以通过未记录的app.config设置来设置,如果设置不存在,则应用正常行为。但是,您需要小心,这不会引入任何漏洞。

答案 4 :(得分:0)

我已经得出结论,以下方法将起作用:

单元测试:

  • 模拟框架,根据需要控制时间

集成测试,用户驱动测试&生产:

  • 依赖注入,用于注入测试方法或生产方法
  • 测试方法:询问NTP服务器的时间。此NTP服务器将连接到所有相关应用程序,而不是服务器,它们都有自己的应用程序。 NTP服务器将标准接口作为标准,允许测试门户或管理员工具等程序根据需要进行更改。
  • 制作方法:询问系统时间,即从NTP服务器连接到所有服务器的时间

以下是调用NTP服务器的C#代码:calling NTP server from C#

拉​​斯