Уже довольно давно я опубликовал пост «Как тестировать код финализатора (c#)», в котором делился опытом тестирования кода, реализованного в финализаторе. Не прошло и года, как тест все-таки упал. Подробности под катом.
Вкратце, был описан способ тестирования, кода финализатора с помощью AppDomain:
[Test]
public void TestTemporaryFile_without_Dispose()
{
const string DOMAIN_NAME = "testDomain";
const string FILENAME_KEY = "fileName";
string testRoot = Directory.GetCurrentDirectory();
AppDomainSetup info = new AppDomainSetup { ApplicationBase = testRoot };
AppDomain testDomain = AppDomain.CreateDomain(DOMAIN_NAME, null, info);
testDomain.DoCallBack(delegate
{
MyTemporaryFile temporaryFile = new MyTemporaryFile();
Assert.IsTrue(File.Exists(temporaryFile.FileName));
AppDomain.CurrentDomain.SetData(FILENAME_KEY, temporaryFile.FileName);
});
string createdTemporaryFileName = (string)testDomain.GetData(FILENAME_KEY);
Assert.IsTrue(File.Exists(createdTemporaryFileName));
AppDomain.Unload(testDomain); // выгружается код и очищается вся память (вызывается финализатор), файл удаляется
Assert.IsFalse(File.Exists(createdTemporaryFileName));
}
Как предчувствовал написал в примечаниях:
3. Скорей всего реализация данного теста, тоже имеет всякие тонкие моменты, но многолетняя практика ни разу не зафиксировала ложное срабатывание этого теста.
Не прошло и года после опубликования этого поста и тест все-таки упал в строчке:
Assert.IsTrue(File.Exists(createdTemporaryFileName));
Это строчка проверяет, что файл, созданный в домейне, все еще существует, хотя объект уже «нет».
Сперва я даже не поверил: запустил раз, еще раз — проходит. Тогда запустил тест с атрибутом Repeat:
[Test]
[Repeat(1000)]
public void TestTemporaryFile_without_Dispose()
{
...
}
и тест упал.
Поэкспериментировал, и получил, что тест падает 7-8 раз за 1000 запусков (0.7%-0.8%) на моем компьютере.
Если я правильно понимаю, то иногда (довольно редко) финализатор объекта вызывается очень быстро и этот тест просто не успеват убедиться, что файл все еще существует.
Мне пришлось отказаться от проверки существования файла: сейчас тест проверяет, что файла нет после выгрузки application domain (AppDomain.Unload).
Теперь, если идти дальше, буду ожидать падение этого теста на проверке отсутствия файла, потому что этот файл (стандартный временный файл) может быть создан заново операционной системой из другого (параллельного) теста или, вообще, другой программой.
Что же я делаю не так?
У меня есть проблема, процесс создает и уничтожает временные файлы, процесс может жить долго, за это время, если плохо удалять созданные временные файлы, они просто физически кончатся и очередная попытка получить у операционной системы временный файл закончится ошибкой.
Итак, я вижу такие варианты:
— проверять случайное падение этого теста раз в какое то время;
— забить на тесты (проверить пару раз ручками);
— не использовать стандартные временные файлы.
Автор: constructor