Может ли кто-нибудь помочь мне объяснить, как 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, также вызывают ResetToDefault() в их отключении Fixture.
- Не используется многопоточный код.
- Время от времени один из модульных тестов выходит из строя, потому что
TimeProvider.Current
имеет значение null (исключение NullReferenceException). - Это происходит только при запуске всего пакета, но не тогда, когда я запускаю только один unit test, предлагая мне, что происходит некоторая тонкая тестовая взаимозависимость.
- Это происходит примерно раз каждые пять или шесть тестовых прогонов.
- Когда происходит сбой, похоже, это происходит в первых выполненных тестах, которые включают
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);
в получателе, и он последовательно сообщает один и тот же идентификатор для всех тестовых примеров в тестовом прогоне, поэтому проблема не связана с потоковой обработкой.