Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Как тестировать код финализатора (c#)

Anna | 18.06.2014 | нет комментариев

Одной из не явственных задач, является тестирование кода, реализованного в финализаторе дотнетовского класса.
Данная заметка рассматривает один из методов решения этой задачи.


Скажем, есть классс MyTemporaryFile (непостоянный файл), тот, что создает неповторимый непостоянный файл в конструкторе и должен удалять его в Dipose() либо в финализаторе.

    public class MyTemporaryFile : IDisposable
    {
        public string FileName { private set; get; }
        public MyTemporaryFile()
        {
            FileName = Path.GetTempFileName();
        }

        public void Dispose()
        {
            Dispose(true);
        }
        ~MyTemporaryFile()
        {
            Dispose(false);
        }

        void Dispose(bool disposing)
        {
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
            DeleteFile();
        }
        void DeleteFile()
        {
            if (FileName != null)
            {
                File.Delete(FileName);
                FileName = null;
            }
        }
    }

Реализация паттерна Dispose достаточно стандартная и обсуждалась на Прогре. Наверно есть в данной реализации некоторые тонкие места, следственно в «настоящей» программе имейте это ввиду.

Но отчего то я не обнаружил обсуждения вопроса, а как же тестировать код, реализованный в финализаторе.

?сно, что «дюже наивная» реализация теста трудиться не будет.

        [Test]
        public void TestMyTemporaryFile_without_Dispose()
        {
            var temporaryFile = new MyTemporaryFile();
            string createdTemporaryFileName = temporaryFile.FileName;

            Assert.IsTrue(File.Exists(createdTemporaryFileName));

            temporaryFile = null;

            Assert.IsFalse(File.Exists(createdTemporaryFileName));
        }

Дело в том, что присвоение null переменной temporaryFile не вызывает финализатор.

Встречался совет вызывать GC.WaitForPendingFinalizers();, но отчего то в данном тесте мне это не помогло.

offtopic: Когда то давным-давно на какой то лекции по c# рассказывали про AppDomain. Я тогда не дюже понимал для чего мне это нужно. Ну вы знаете, как множество лекторов рассказывают для “некого среднего слушателя” “некие всеобщие вещи“. Я ни разу не сумел осознать паттерн Dispose со слов лектора. Самое смешное, что позже того, как я стал его чуть чуть понимать, я с трудом стал предполагать, что лектор таки имеет ввиду. 

Так вот, оказывается, что с поддержкой 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)); 
        }

Как вестимо, AppDomain.Unload(testDomain); выгружает код и очищает память (в том числе и вызываются финализаторы).
Это и помогает «насильственно вызвать» финализатор и, соответсвенно, протестировать его код.

Примечания:
1. Один из лекторов советовал в финализаторе выкидывать исключительную обстановку (exception) со словами “вызови Dispose, дурак“. Где то он может быть и прав, но если есть unmanaged источник, нужно предусмотреть и финализатор тоже.
2. Реализация класса MyTemporaryFile дюже схематична и не рекомендуется для продакшен применения.
3. Скорей каждого реализация данного теста, тоже имеет каждые тонкие моменты, но многолетняя практика ни разу не зафиксировала ложное срабатывание этого теста.
4. С удовольствием почитаю, как дозволено решить задачу тестирования финализатора другими методами либо какие есть недочеты у данного подхода.

 

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB