【发布时间】:2011-02-19 21:26:45
【问题描述】:
谁能帮我解释一下TimeProvider.Current如何在下面的课程中变为空?
public abstract class TimeProvider
{
private static TimeProvider current =
DefaultTimeProvider.Instance;
public static TimeProvider Current
{
get { return TimeProvider.current; }
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
TimeProvider.current = value;
}
}
public abstract DateTime UtcNow { get; }
public static void ResetToDefault()
{
TimeProvider.current = DefaultTimeProvider.Instance;
}
}
观察
- 所有直接引用 TimeProvider 的单元测试也会在其 Fixture Teardown 中调用 ResetToDefault()。
- 没有涉及多线程代码。
- 有时,其中一个单元测试会失败,因为
TimeProvider.Current为 null(抛出 NullReferenceException)。 - 这仅在我运行整个套件时发生,但在我只运行单个单元测试时不会发生,这表明存在一些微妙的测试相互依赖性。
- 大约每五六次测试运行一次。
- 当发生故障时,它似乎发生在涉及
TimeProvider.Current的第一个执行测试中。 - 可能不止一项测试失败,但在给定的测试运行中只有一项失败。
FWIW,这里也是 DefaultTimeProvider 类:
public class DefaultTimeProvider : TimeProvider
{
private readonly static DefaultTimeProvider instance =
new DefaultTimeProvider();
private DefaultTimeProvider() { }
public override DateTime UtcNow
{
get { return DateTime.UtcNow; }
}
public static DefaultTimeProvider Instance
{
get { return DefaultTimeProvider.instance; }
}
}
我怀疑静态初始化存在一些微妙的相互作用,在所有静态初始化完成之前实际上允许运行时访问TimeProvider.Current,但我不能完全确定它。
感谢任何帮助。
FWIW 我刚刚扔了
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
在 getter 中,它始终为测试运行中的所有测试用例报告相同的 ID,因此问题似乎与线程无关。
【问题讨论】:
-
如果使用静态构造函数而不是静态字段初始化,是否也会发生这种情况?在 DefaultTimeProvider 上。
-
我把这个放在我的博客上,因为我在查找环境上下文的细节时遇到了一些问题 - 希望你不介意:relentlessdevelopment.wordpress.com/2013/09/30/…
-
我在 MVVM 框架 Caliburn.Micro 及其扩展库 Caliburn.Micro.Contrib 中遇到过类似的情况。使用扩展库中的这个 [原始代码] (pastebin.com/0eydNkEQ),我无法在 Visual Studio 之外运行我的 WPF 应用程序(但我可以很好地调试应用程序)。据我记得,我得到了 Stack Overflow 异常,因为 _baseTransformName 字段被分配了 FallbackNameTransform 方法,并且该方法由框架通过 ViewLocator.TransformName 调用。我不得不使用 [此解决方法] (pastebin.com/Z4hVLzUm)。
标签: c# .net unit-testing static abstract-class