Как провести модульный тест IDisposable?

Я работаю над частью кода библиотеки вокруг IDisposable. Управляемый путь (через using) легко проверить. Однако меня интересует финализатор: достаточно ли вызова System.GC.Collect() для принудительного финализатор запустить?


person David Schmitt    schedule 29.10.2008    source источник
comment
Если вы придерживаетесь предписанного шаблона для IDisposable, я уверен, что модульное тестирование будет очень полезным.   -  person Mitch Wheat    schedule 29.10.2008
comment
извините, это должно было быть, я не уверен, что модульное тестирование будет таким полезным...   -  person Mitch Wheat    schedule 29.10.2008
comment
@Mitch: правильная реализация IDisposable, чтобы управляемые и неуправляемые ресурсы удалялись в нужный момент, нетривиальна. Поскольку рассматриваемый код библиотеки отвечает именно за это, я не вижу смысла не тестировать это...   -  person David Schmitt    schedule 29.10.2008
comment
stackoverflow.com/a/17014062/339384   -  person constructor    schedule 27.04.2015


Ответы (4)


Нет, вызов GC.Collect() асинхронный, вам также нужно будет вызвать это:

System.GC.WaitForPendingFinalizers();
person RickL    schedule 29.10.2008
comment
Я думаю, что сам GC.Collect() является синхронным (т. е. он освободит всю доступную память к тому времени, когда он вернется), но сами финализаторы запускаются отдельно. Хотя я могу быть совершенно не прав... - person Jon Skeet; 29.10.2008
comment
Делаю и сейчас и тест каждый раз проходил. То есть вызывается правильная точка расширения из финализатора. - person David Schmitt; 30.10.2008
comment
Примечание для себя: также проверьте, что код инициализации рассматриваемого класса не является корневым объектом где-либо. - person David Schmitt; 31.10.2008
comment
@EricBurcham: пример, где я это использую, находится здесь: github.com/ daszat/zetbox/blob/master/Tests/ - person David Schmitt; 19.02.2014
comment
это не работает для меня. Я позвонил GC.Collect(), а затем GC.WaitForPendingFinalizers(); и ни разу не disposing никогда false - person Matthew; 24.07.2019

Я бы посмотрел на удаление, завершение, и управление ресурсами это лучший справочник по теме, о которой я знаю. Используя их шаблон:

~ComplexCleanupBase()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected override void Dispose(bool disposing)
{
   if (!disposed)
   {
        if (disposing)
        {
            // dispose-only, i.e. non-finalizable logic
        }

        // new shared cleanup logic
        disposed = true;
    }

    base.Dispose(disposing);
}

Вы получаете мертвые простые методы Finalizer/Dispose() и проверяемый Dispose(bool). Не нужно форсировать Finalization или что-то еще, используя класс GC.

person Rob McCready    schedule 11.02.2009
comment
Да, я делаю это примерно так. Это лишь небольшая адаптация того, что рекомендуется в MSDN. - person David Schmitt; 12.02.2009

Не могли бы вы смоделировать интерфейс IDisposable и ожидать вызова Dispose? Это, по крайней мере, позволит вам увидеть, когда объект действительно утилизируется.

person brien    schedule 29.10.2008
comment
Чтобы обнаружить это, достаточно установить точку останова. Однако я тестирую реализацию Dispose(), а не то, вызывается ли она. - person David Schmitt; 24.01.2009

Я думаю, что я бы склонялся к тому, чтобы Finalize() вызывал другой метод и проверял, что другой метод делает то, что вы хотите. Вы не получите 100% покрытия кода, но, по крайней мере, будете знать, что метод правильно освобождает ресурсы объекта.

person Ben Fulton    schedule 29.10.2008