C# 应用程序时间的设计模式?
如果您构建的系统中的业务流程取决于时间[1],则不能在代码中使用C# 应用程序时间的设计模式?,c#,design-patterns,testing,C#,Design Patterns,Testing,如果您构建的系统中的业务流程取决于时间[1],则不能在代码中使用DateTime.Now或类似内容,因为您将必须处理测试,例如,未来的月末或年末场景。当您使用SSL证书时,更改操作系统时间通常不是一个选项,因为对分布式系统进行正确操作很复杂 一个选项是创建一个可由所有系统访问并返回当前时间的单例服务。在生产中,它可以返回日期时间。现在,在测试中,它可以返回一个游戏时间,如月末场景中的2月28日 但是有没有更好的方法呢?是否喜欢更面向数据库的方法,因为它可以带来更好的性能?或者你会放在一个分布式缓
DateTime.Now
或类似内容,因为您将必须处理测试,例如,未来的月末或年末场景。当您使用SSL证书时,更改操作系统时间通常不是一个选项,因为对分布式系统进行正确操作很复杂
一个选项是创建一个可由所有系统访问并返回当前时间的单例服务。在生产中,它可以返回日期时间。现在,在测试中,它可以返回一个游戏时间,如月末场景中的2月28日
但是有没有更好的方法呢?是否喜欢更面向数据库的方法,因为它可以带来更好的性能?或者你会放在一个分布式缓存中?有什么著名的设计模式吗
[1]典型示例:保险系统、核心银行系统等实施的业务流程处理此问题的一种方法是: 并在整个代码中使用此界面,而不是
DateTime.Now
。在生产中,您将使用其规范实现(或UTC变体):
例如,您可以在需要IClock
的所有类中使用SystemClock
作为默认值,并允许通过构造函数或setter注入其他实现
在测试中,您可以创建测试实现或使用模拟框架对其进行模拟。您可以研究如何使用来实现您所说的内容
看这个稍加修改的例子
[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的代码以使其可测试。对于单元测试,您应该能够删除任何内容,包括时间。一些模拟框架(例如)允许您覆盖DateTime.Now的行为
对于集成/系统测试,我过去所做的是为每个系统组件使用一个配置设置,该设置指定该组件从实时日期时间使用的日期时间偏移量。这可以通过未记录的app.config设置进行设置,如果没有设置,则应用正常行为。但是,您需要注意,这不会引入任何漏洞 如果日期和时间是关键和复杂的(特别是由于时区和DST),我想您提到的行业就是这样,您可能希望避免使用
野田佳彦拥有内置的单元测试功能,请参见我得出结论,以下方法将有效: 单元测试:
- 模拟框架,根据需要控制时间
- 依赖注入,用于注入测试方法或生产方法
- 测试方法:询问NTP服务器现在的时间。此NTP服务器将连接到所有相关应用程序,而不是服务器,因为服务器有自己的应用程序。NTP服务器将有一个标准接口,允许测试门户或管理员工具等程序根据需要对其进行更改李>
- 生产方法:询问系统时间,即从NTP服务器连接到所有服务器的时间
Lars我喜欢在正常测试中使用类似于赝品的框架来控制时间。您还可以使用Unity从生产代码中提取时间,这意味着您可以在测试和DateTime.Now中注入游戏时间。但是,当您为金融部门构建更大的系统时,您不能完全依赖这种方法,因为这些类型的测试通常是用户驱动的。一个普通示例:管理员(可以是业务人员)将一组新的业务参数(如利率)上载到测试环境,并希望从业务角度验证系统的反应。他们必须能够改变时间。
public class SystemClock implements IClock {
public DateTime Now { get { return DateTime.Now; } }
}
[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);
}
}