на тестовой машине нет пользователей (не злобных, не добрых). добрый этот, который снимает read-only после злобного :).
а программистам я доверяю.
поэтому пусть тест валится.
Вообще то я использую и реализацию временных файлов через GUID. Когда мне понадобился временный файл с определенным расширением мне пришлось перейти на GUID.
б) вы сможете лучше контролировать время жизни файлов: вместо танцев с тестами финализатора создавайте файлы с FileOptions.DeleteOnClose — сама ОС позаботится, что файл будет удалён, даже если ваш процесс вообще упадёт с ошибкой.
FileOptions.DeleteOnClose() существенное преимущество над Path.GetTempFileName(). Надо будет воспользоваться этой идеей. Но, как мне кажется, принципиально это ничего не меняет.
Действительно, она накладывает ограничения на количество файлов, что и заставляет меня искать причины, почему временные файлы не удалятся. Один из способов защиты — это тестирования обертки «временный файл».
Мне кажется, что вы сами и ответили: если использовать Path.GetTempFileName, то временные файлы кончатся. И такие ситуации я встречал на практике.
Я понимаю, что один из способов это использовать самопальные временные файлы, что теоретически (в случае, если удаление реально не выполняется), только увеличивает время жизни процесса, до того, как кончится место на диске :).
Недавно чистил временную папку. Так было что почистить :).
Я согласен, что есть внешние обстоятельства, которые проверять не очень можно. Но есть сценарий, где есть место и для тестов.
Например, если моя обертка «временный файл», открывыает файл в конструкторе и должна его закрыть перед финализатором.
В этом случае, проверка того, что финализатор вызывает удаление файла хорошо для unit теста, но не достаточна для интеграционного теста. Мне важно убедиться, что файл будет удален.
Если попробовать обобщить, то есть некий внешний ресурс, с которым работает обертка и важно убедиться, что эта работа корректная (с точки зрения внешнего ресурса, причем не всегда мы знаем как он себя ведет).
Вам достаточно проверить, что ваш код вызывает File.Delete и съедает все исключения
К сожалению не всегда достаточно. Мне очень важно убедиться, что файл действительно будет удален. Может быть мой код открыл файл и не закрыл, и тогда тест должен упасть, иначе проблема будет скрыта и обнаружется только тогда, когда кончаться временные файлы
В этот момент никакой финализатор не вызывается, здесь происходит выгрузка из памяти, именно очищение. Вашего объекта в этот момент то уже и нет, объект удалился, когда вы вышли из анонимного метода, где было единственное его упоминание.
Как справедливо многие здесь пишут
нет никаких гарантий что финализатор вообще отработает, а если и отработает, то никто, даже сама платформа, не знает когда он отработает
. Следовательно, нужно как то заставить вызвать финализатор. Один из способов, это вызывать выгрузку домайна.
Мне кажется у вас неверно поставлена задача. Как вам уже отвечали в прошлой статье, нет никаких гарантий что финализатор вообще отработает, а если и отработает, то никто, даже сама платформа, не знает когда он отработает.
И тем не менее, с большой вероятностью финализатор отработает (в реальном длительном процессе), и следовательно, вполне логично, в финализаторе написать код, который будет удалять внешний ресурс (если Dispose не был вызван).
Мне кажется это очень логичным. И если есть код в финализаторе, то мне хочется иметь для него тест.
Как мне помнится, сборщик мусора один на все, и к тому моменту, как у вас подходит дело к проверкt а удален ли файл, финализатор может вообще еще не отработал, и это не значит, что код сломался.
Вот для этого, я и написал об использовании AppDomain, что бы заставить вызать финализатор к тому времени, когда будет проверяться отсутствие файла.
Если вам нужно обязательно удалять файл, тогда требуется использовать патерн Disposable и явным образом вызывать метод Dispose.
use (var file = new TempFile()){
SomeOperations();
}
В простых случаях так и реализовано, но есть ситуации где код более сложен.
Кстати, для нахождения таких ситуаций, когда Dispose() не вызывался, я добавил конструкторе сохранения стека вызова, а в финализаторе сделал вывод этого стека в консоль. Такой способ помог мне найти и частично решить проблемы не вызова Dispose()
3.
мне нужет еще тест для проверки того, что файл действительно удаляется
Вам не нужно тестировать File.Delete. Это уже не ваша забота. Что стоит протестировать — это факт того, что File.Delete вызывается. Для этого в Visual Studio есть Fake Assemblies.
Для unit-теста это не моя забота. Опять согласен.
Но для более другого теста, это моя забота. Мне нужно быть уверенным, что финализатор не только вызовет удаление файла, но и удалит его.
2. В чём смысл тестирования единственной строки Dispose(false) — а именно таким обычно и бывает финализатор? Хотите протестировать финализатор? Тестируйте Dispose(false).
Смысл тестирования, убедиться (и убеждаться все время и при всяких изменениях), что финализатор вызывает удаление файла.
Интересно, стоит ли писать модульный тест для проверки удаления временного файла? По моему мнению да. Тогда интересно как этот тест может быть реализован?
Кстати, я понимаю, что тест сложен (по сравнению с кодом), но моя цель избежать сложных проблем при длительном реальном использовании программы, и это требует, в данном случае, сложный тест.
2. В предыдущей статье, уважаемый mayorovp уже упоминал возможность удаления всех временных файлов при закрытии процесса, но там велась речь о решении с помощью P/Invoke. На самом деле есть стандартная обертка над этим флагом.
Не совсем понимаю, как это может помочь в случае использования Path.GetTempFileName. Не хотелось бы переходить на собственную реализация «временных» файлов.
По моему скромному мнению, код вашего финализатора тестировать не стоит(по крайней мере с помощью unit-теста).
Готов написать два теста: unit тест для проверки, что вызывается удаление файла, но мне нужет еще тест для проверки того, что файл действительно удаляется.
Кстати, «тестировать не стоит» потому что это тестируется глазками, или потому что, нет нормального способа?
Я хотел написать тест для двух целей: с одной стороны убедиться, что финализатор вызывает удаление файла, а с другой стороны убедиться, что файл будет удален. Ваши предложения хороши для первой части, но главная трудность тут во второй.
а программистам я доверяю.
поэтому пусть тест валится.
FileOptions.DeleteOnClose() существенное преимущество над Path.GetTempFileName(). Надо будет воспользоваться этой идеей. Но, как мне кажется, принципиально это ничего не меняет.
Я понимаю, что один из способов это использовать самопальные временные файлы, что теоретически (в случае, если удаление реально не выполняется), только увеличивает время жизни процесса, до того, как кончится место на диске :).
Недавно чистил временную папку. Так было что почистить :).
Например, если моя обертка «временный файл», открывыает файл в конструкторе и должна его закрыть перед финализатором.
В этом случае, проверка того, что финализатор вызывает удаление файла хорошо для unit теста, но не достаточна для интеграционного теста. Мне важно убедиться, что файл будет удален.
Если попробовать обобщить, то есть некий внешний ресурс, с которым работает обертка и важно убедиться, что эта работа корректная (с точки зрения внешнего ресурса, причем не всегда мы знаем как он себя ведет).
К сожалению не всегда достаточно. Мне очень важно убедиться, что файл действительно будет удален. Может быть мой код открыл файл и не закрыл, и тогда тест должен упасть, иначе проблема будет скрыта и обнаружется только тогда, когда кончаться временные файлы
Интересный подход. Можете посоветовать, что то конкретное? Какой инструмент и как эту проверку задать?
Как справедливо многие здесь пишут . Следовательно, нужно как то заставить вызвать финализатор. Один из способов, это вызывать выгрузку домайна.
И тем не менее, с большой вероятностью финализатор отработает (в реальном длительном процессе), и следовательно, вполне логично, в финализаторе написать код, который будет удалять внешний ресурс (если Dispose не был вызван).
Мне кажется это очень логичным. И если есть код в финализаторе, то мне хочется иметь для него тест.
Вот для этого, я и написал об использовании AppDomain, что бы заставить вызать финализатор к тому времени, когда будет проверяться отсутствие файла.
В простых случаях так и реализовано, но есть ситуации где код более сложен.
Кстати, для нахождения таких ситуаций, когда Dispose() не вызывался, я добавил конструкторе сохранения стека вызова, а в финализаторе сделал вывод этого стека в консоль. Такой способ помог мне найти и частично решить проблемы не вызова Dispose()
Для unit-теста это не моя забота. Опять согласен.
Но для более другого теста, это моя забота. Мне нужно быть уверенным, что финализатор не только вызовет удаление файла, но и удалит его.
Согласен, поэтому я и написал, что допустим unit-тест перепишу, но интересно обсудить как написать тест, который проверит удаление файла.
Смысл тестирования, убедиться (и убеждаться все время и при всяких изменениях), что финализатор вызывает удаление файла.
Интересно, стоит ли писать модульный тест для проверки удаления временного файла? По моему мнению да. Тогда интересно как этот тест может быть реализован?
Кстати, я понимаю, что тест сложен (по сравнению с кодом), но моя цель избежать сложных проблем при длительном реальном использовании программы, и это требует, в данном случае, сложный тест.
Нельзя создать два временных файла с одним и тем же расширением? Если да, то это сильно ограничивает область использования TempFileCollection.
Не совсем понимаю, как это может помочь в случае использования Path.GetTempFileName. Не хотелось бы переходить на собственную реализация «временных» файлов.
Готов написать два теста: unit тест для проверки, что вызывается удаление файла, но мне нужет еще тест для проверки того, что файл действительно удаляется.
Кстати, «тестировать не стоит» потому что это тестируется глазками, или потому что, нет нормального способа?