我遇到了这个问题about dealing with DateTime.Now in unit tests的接受答案,其中包含以下代码示例:
private readonly Func<DateTime> _nowProvider;
public SomeClass(Func<DateTime> nowProvider)
{
_nowProvider = nowProvider;
}
public bool Foo()
{
return (_nowProvider().DayOfWeek == DayOfWeek.Sunday);
}
实例化:
var s = new SomeClass(() => DateTime.Now);
我在C#中使用Func<T>
的时间并不多,所以我想我会看一下at the Microsoft documentation for it,其中有以下几点:
您可以使用此委托来表示可以作为参数传递的方法,而无需显式声明自定义委托。封装的方法必须对应于此委托定义的方法签名。这意味着封装的方法必须没有参数,并且必须返回一个值。
为什么在示例中传递Func<DateTime>
,将Class(() => DateTime.Now)
实例化为构造函数
而不是简单地将实例化为DateTime
的{{1}}参数传递给构造函数?
根据上面提到的Microsoft文档,LINQ lambda构造函数也接受Class(DateTime.Now)
个参数,我对这些参数的经验证明它们非常灵活,但我无法理解为什么?
答案 0 :(得分:6)
而不是简单地将实例化为Class(DateTime.Now)的DateTime参数传递给构造函数?
因为该值应该是当前的DateTime而不是该类已实例化时的值。
当代码运行时,Func将返回完全代码执行时的日期。
如果DateTime将存储在一个字段中,那么它将是创建时间,而不是现在。
我有一个例子。
假设您在星期六23:59:55创建Class
的实例。
10秒后,以下剪辑:
(passedDateTime.DayOfWeek == DayOfWeek.Sunday);
会返回false。
使用提供程序时,日期时间实际上是星期日 - 它执行的时间。
技术:
DateTime是一个结构。
将DateTime作为参数传递给方法或构造函数时,它将作为值传递,而不是作为引用传递。
因此DateTime
不会是最新的,而只是值的快照。
您可以自己确认:
var dateTime = DateTime.Now;
System.Threading.Sleep(1000);
bool equals = dateTime == DateTime.Now; // false
答案 1 :(得分:3)
此模式允许在正常操作期间由DateTime.Now
提供日期和时间,或在单元测试期间进行严密控制。
例如,想要测试基于时间的功能的单元测试可以在每次调用(一种常见的缓存技术)之间调用两次超过5分钟的函数时验证返回的结果是否正确,而无需等待5电话之间的分钟数。
这也是&#34;控制反转的一个例子。图案。检索数据的方法是注入&#34;在课堂上,通常是通过构造函数。然后,该类可以自由地使用注入的任何方法而不了解其实现。
答案 2 :(得分:2)
我附上了一个小例子,说明在单元测试中它的样子。
如果你没有能力提供不同的&#34;现在&#34;单元测试的运行时间会有所不同。
[TestMethod]
public void TestFoo()
{
var obj = new SomeClass(() => DateTime.Now);
//Only true on sundays
Assert.IsTrue(obj.Foo());
//This is sunday
obj = new SomeClass(() => new DateTime(2017, 7, 30));
//This will be always true
Assert.IsTrue(obj.Foo());
//This is not sunday
obj = new SomeClass(() => new DateTime(2017, 7, 29));
//This will be always false
Assert.IsFalse(obj.Foo());
}