Юнит тесты для "системного" приложения
Для задачи
https://foren.germany.ru/showmessage.pl?Number=37847327&Bo...
...
Остальное в следующем посте
Как то привык логику тестировать. А тут работа с файлами и системой.
Можно конечно всё тестовыми заглушками заменить, но не вижу большого смысла. Только для того чтобы тесты были...
Копируем допустим файл, на диске места больше нет.
Или скопировали десяток больших файлов. Или...
Это же целую модель системы надо делать.
А как проверить что реагирует только на файлы, а не на каталоги.
Если я правильно понял и обертки это моки, то (на яве, по крайней мере) создаем моки для ввода и вывода и отлавливаем на выводе все, что выходит. Создаем сценарии тестов, отлавливаем на выходе одного и того же мока результрат и сравниваем с ожидаемым.То есть тестов много, сценариев много, а вот мок вывода один.
А вот времена и размеры будут роль играть.Юниттесты нe проверяют перформанs
Нужно определиться что и для чего. Юниттесты только защищают целостность и функтиональность кода.
Копируем допустим файл, на диске места больше нет.
Униттесты не проверяют состояния окружения, но они проверяют реакцию кода на определенные ответы опрошенного окружения. Сами запросы выполняют системные функции. Заменяем системную функциию на мок и симулируем ситуацию(вручную выбрасываем ошибкu). Проверяем реакцию собственного кода.
и обертки это моки
Не знаю что там в Яве и что имелось в виду. Я понимаю обвертку так.
internal class DirectoryWatcher: IDirectoryWatcher { public event EventHandler<FileSystemEventArgs> NewFileAdded; private readonly FileSystemWatcher _watcher = new FileSystemWatcher(); public void Start(string directoryName) { _watcher.Path = directoryName; // Watch files only. _watcher.IncludeSubdirectories = false; // Watch all files. _watcher.Filter = "*.*"; _watcher.Created += Watcher_Created; //Start monitoring. _watcher.EnableRaisingEvents = true; } public void Stop() { //Stop monitoring. _watcher.EnableRaisingEvents = false; } private void Watcher_Created(object sender, FileSystemEventArgs e) { //e.FullPath NewFileAdded?.Invoke(sender, e); } }
Юниттесты нe проверяют перформанs
Так меня не скорость интересует, а функциональность. Просто в данном случае всё сильно зависит от количества и размеров файлов на входе.
Сейчас я всё делаю сразу после поступления события о приходе нового файла. А может нужно это всё в очередь записывать?
Ну и другое. Как проверить пароль перед стартом проги в юнит тестах. Дело в том что если ничего не делать, то прога просто не запуститься после запуска окна ввода пароля.
Для данного случая мне кажется что разработка юнит тестов займет гораздо больше времени чем они принесут пользы.
Как то привык логику тестировать. А тут работа с файлами и системой.
Можно конечно всё тестовыми заглушками заменить, но не вижу большого смысла. Только для того чтобы тесты были...
Перед тем, как написать тест надо ответить на один вопрос - что я хочу протестировать?
Работу системных функций, которые работают с файлами тестировать не надо. Все эти функции уже 100500 раз протестированы и надо исходить из того, что они не содержат ошибок.
Значит у тебя есть некая логика, в которой есть некоторое количество вызовов системных функций. Ну а логику тестировать ты уже привык :) Осталось только абстрагироваться от системных вызовов. Сделать это можно одним простым способом - выделив эти функции на другой уровень и соеденив этот уровень со своим кодом через некий интерфейс (контракт).
Если не хочется городить все это ради тестов, то всегда можно сделать "системные тесты". Правда системные тесты а) медленнее и б) не могут протестировать все тонкости, например "на диске места больше нет" :)
Так что тут уж придется тебе делать выбор :)
Это же целую модель системы надо делать.
Да, ну или выделять какие-то важные для тебя части и моделировать только их. Я когда-то делал обертку для доступа в реестр.
а функциональность. Просто в данном случае всё сильно зависит от количества и размеров файлов на входе.
Что изменится. если количество файлов увеличится в 10 раз? будет подключен другой обработчик? Изменится результат?
Как проверить пароль перед стартом проги в юнит тестах. Дело в том что если ничего не делать, то прога просто не запуститься после запуска окна ввода пароля.
Юниттесты не проверяют прогу. И для тестов прога не запускается. Юниттесты проверяют юниты - куски програмного кода, один или несколько вызовов функций. Изолировано.
То, что ты пытаешься запустить это интегратионтест в тестовом окружении. Если хрень запускается в броузере, работу юзера можно симулировать силениумоm
надо ответить на один вопрос - что я хочу протестировать?
В данном случае написано надо
Работу системных функций, которые работают с файлами тестировать не надо.
А я и не хочу именно их тестировать, я могу просто неправильно задать параметры для их вызова.
выделив эти функции на другой уровень
ну они как бы и выделены. Но для тестов
- нужно писать свою имплементацию
- передавать ее в конструктор
А так как этих уровней минимум три+экспорт+настиройки, то вся работа по тестированию будет сопоставима по затратам с написанием кода и даже больше.
Для данного случая мне кажется что разработка юнит тестов займет гораздо больше времени чем они принесут пользы.
Юниттесты не приносят пользу. Они защищают. Допустим есть код, этот код протестован вручную или другим способом и никогда не будет менятся. ВСЕ. Юниттесты никакой пользы больше не принесут.
А вот если ты грузишь путь доступа из конфигурационного файла, а коллега для тестов втихоря заменил его и в коде временно прописал свой путь, забыл и загнал код в репозиторий, то тест заорет раньше, чем код рухнет у клиента.
У нас деятели повадились отключать ССЛ-шифрование у рест-ендпойнтов. Приложение стартует. Пока к нему кто то не попробует подконнектится. Закрыли юниттестами.
А так как этих уровней минимум три+экспорт+настиройки, то вся работа по тестированию будет сопоставима по затратам с написанием кода и даже больше.
Во первых да. Часто написание Юниттестов сопоставимо с написанием кода. Во вторых если мы хотим от затычки особой функтиональности, то это уже спай - шпион.
я могу просто неправильно задать параметры для их вызова.
Не бывает неправильных параметров, бывают ответы системных функций. Честь из них это нормальные ответы, часть - сообщения о ошибках. Все эти варианты документируемы. Тестировать надо , как собственный код ресгирует на любой вариант ответа системной функции. То есть не "неправильные" или "правильные" параметры совать, а сразу моком выбрасывать необходимый для данного теста результат.
Если есть возможность формализовать утверждение, что такое "неправильный" параметр, то такой опработчик и его тест надо делать до вызова системной функциi
Что изменится. если количество файлов увеличится в 10 раз?
- Копируем файл в каталог
- Получаем уведомление о добавлении файла
- Сжимаем файл
- Перемещаем файл
пункт 2 занимает определенное время. И вся цепочка будет работать совершенно по разному в зависимости от количества и размера одновременно копируемых файлов.
Вот сейчас, например. В юнит тесте Зип работает без проблем, а обработчике выдает ошибку.
Юниттесты не приносят пользу. Они защищают.
А мне и не нужно ничего защищать. Я только хочу проверить работу проги на граничных условиях. Да и вообще что бы не сломал.
Вод делаю я XAML парсер, так у меня этих тестов на каждый чих: <tag>, <tag\r\n>, <\r\ntag> и т.п.
Явная польза.
А тут изменил не заглушку, а реальную обвертку и всё тебе уже поступают каталоги а не файлы.
пункт 2 занимает определенное время.
Это не функтиональность. Это производительность. Юниттесты не тестируют производительность.
И вся цепочка будет работать совершенно по разному
Если я правильно понял, то абсолютно также. Но дольше. Юниттесты это не тестируют. Они тестируют только принципиальные различия. Например допускается только 50 файлов. При наличии > 50 файлов должен сработать ДРУГОЙ кусок кода. Это принципиальное различие, это можно тестировать.
В юнит тесте Зип работает без проблем, а обработчике выдает ошибку.
Более того. У меня в реале зип выдаст ошибку, у соседа нет. Надо тестировать не зип. Нужно тестировать код, использующий зип. А зип выдавал и будет выдавать ошибки по независящим от кода причинам. Юниттесты тестируют только код.
В данном случае написано надо
И как, ответ-то уже есть? :)
А я и не хочу именно их тестировать, я могу просто неправильно задать параметры для их вызова.
Не понимаю.
ну они как бы и выделены. Но для тестов 1. нужно писать свою имплементацию 2. передавать ее в конструктор
1) определить интерфейс
2) сделать класс, который имплеметрирует этот интерфейс
3) передавать в конструктор можно и это пожалуй наиболее простое решение. Можно использовать какой-нибудь контейнер. Например Ninject. Но есть и другие способы.
Это не функциональность. Это производительность.
reentrancy - производительность?
Если я правильно понял, то абсолютно также
Могу логов нафигачить если не веришь, хоть и не проверял еще
Нужно тестировать код, использующий зип.
и что тут тестировать FileCompressor.Compress(destFilePath); ?
И как, ответ-то уже есть?
В смысле? На какой вопрос?
Не понимаю.
Ну вот кусок кода для настройки. Вроде всё верно. А гад реагирует на копирование каталога.
_watcher.Path = directoryName;
// Watch files only.
_watcher.IncludeSubdirectories = false;
// Watch all files.
_watcher.Filter = "*.*";
_watcher.Created += Watcher_Created;
//Start monitoring.
_watcher.EnableRaisingEvents = true;
Можно использовать какой-нибудь контейнер. Например Ninject.
никогда в моем коде не будет DI Container. И фиг поймешь как работает система, когда оно везде. И непонятно как отлаживать. Был уже такой проект.
Но есть и другие способы.
и какие интересно?
В любом случае нужно писать два класса, один тестовый и один реальный. Для одного случая еще как то можно и то неизвестно.
Вот например, в заглушке фиг бы додумался сразу - файл нужно вначале загнать в зип и при создании зип файла будет "ложное" извещение о копировании файла в каталог.
На какой вопрос?
Что ты хочешь тестировать?
Ну вот кусок кода для настройки. Вроде всё верно. А гад реагирует на копирование каталога.
_watcher.Path = directoryName;
// Watch files only.
_watcher.IncludeSubdirectories = false;
// Watch all files.
_watcher.Filter = "*.*";
_watcher.Created += Watcher_Created;
//Start monitoring.
_watcher.EnableRaisingEvents = true;
Это мило, то тут ты конфигурируешь некий объект _watcher. Никакой логики тут нет. Цикломатическая сложность этого кода равна 1.
Но предположим, что ты хочешь получить ошибку (исключение) в момент, когда выполныешь строку _watcher.EnableRaisingEvents = true; если directoryName - директория. И не получать исключение, если directoryName - файл.
В таком случае у тебя есть такой код:
public interface ISystemFile { System.IO.FileAttributes GetAttributes(string path); } public class SystemFile : ISystemFile { public FileAttributes GetAttributes(string path) { return System.IO.File.GetAttributes(path); } } public class FileSystemWatcher { ISystemFile _systemFiles = null; public FileSystemWatcher() : this (new SystemFile()) { } public FileSystemWatcher(ISystemFile systemFiles) { _systemFiles = systemFiles; } public string Path { get; set; } public bool IncludeSubdirectories { get; set; } public string Filter { get; set; } public event EventHandler Created; private bool _enableRaisingEvents = false; public bool EnableRaisingEvents { get { return _enableRaisingEvents; } set { if (value == true) { System.IO.FileAttributes att = _systemFiles.GetAttributes(Path); if (att == System.IO.FileAttributes.Directory) throw new Exception("blah-blah-blah"); } _enableRaisingEvents = value; } } }
Ну и тестируешь то, что надо:
[TestMethod] public void EnableRaisingEvents_TrueForFile_OK() { // Arrenge ISystemFile systemFile = Substitute.For<ISystemFile>(); systemFile.GetAttributes(Arg.Any<string>()).Returns(FileAttributes.Normal); FileSystemWatcher watcher = new FileSystemWatcher(systemFile); // Act watcher.EnableRaisingEvents = true; // Assert Assert.IsTrue (watcher.EnableRaisingEvents); } [TestMethod] [ExpectedException(typeof(Exception))] public void EnableRaisingEvents_TrueForDirectory_Exception() { // Arrenge ISystemFile systemFile = Substitute.For<ISystemFile>(); systemFile.GetAttributes(Arg.Any<string>()).Returns(FileAttributes.Directory); FileSystemWatcher watcher = new FileSystemWatcher(systemFile); // Act watcher.EnableRaisingEvents = true; // Assert }
и какие интересно?
Ну например тоже сделать виртуальную функцию, которая будет возвращать реальную обертку. В тесте такую функцию можно перегрузить.
reentrancy
Попробуй на примере сформулировать, что конкретно ты хочешь протестировать, увеличив количество файлов? То, что ты тестируешь - это ТВОЙ код или ты пытаешься посмотреть, как работает сторонняя библиотека? Именно твой код меняет поведение от количества файлов?
Могу логов нафигачить если не веришь, хоть и не проверял еще
Не надо. Опиши словами. Что должно произойти от увеличения количества файлов? Если ты используешь слова "быстрее", то это производительность.
и что тут тестировать
Только выzов самой функции. Вызывается и сколько раз вызывается. Это не твой код. Тут нечего тестировать.
На какой вопрос? Что ты хочешь тестировать?
Вообще то не вижу ничего, что имеет смысл покрывать юнит тестами.
Можно только создать сферического коня в вакууме и его тестировать
Это мило, то тут ты конфигурируешь некий объект _watcher. Никакой логики тут нет
Естественно, но именно так и не работает
Нужно было добавить еще одну строку
_watcher.NotifyFilter = NotifyFilters.FileName;
А что ты там тестируешь я так и не понял, для меня это какое то извращение, тем более что я пользую NUnit
Это не каталог. Это строка. В принципе путь к файлу, но вообще строка.
ну так в том то и дело. Не имеет значения, что я кидаю файл или каталог на выходе одна и таже строка.
И там еще буфер в 4К по умолчанию. Так что неизвестно будет ли работать для 1000 файлов и больше.
Если ты используешь слова "быстрее", то это производительность.
В данном случае от скорости меняется логика.
Я начинаю вызывать функцию по новому, когда она еще не закончила свою работу.
Кроме того как в "эмуляторе" отследить что эта функция создала новый файл к каталоге для мониторинга
Только выzов самой функции. Вызывается и сколько раз вызывается.
А на кой мне эвент тестировать? Сколько раз его вызвал столько и придет, вроде как системная функция.
Вообще то не вижу ничего, что имеет смысл покрывать юнит тестами.Можно. А можно задуматься о том, где могут быть проблемы в твоем коде и как смоделировать эти проблемы.
Можно только создать сферического коня в вакууме и его тестировать
Короче говоря можно попробовать ответить на следующие вопросы:
1) что является твоим Unit under test?
2) какие требования предъявляются к твоему Unit under test?
3) с какими объектами взаимодействуешь твой Unit under test?
Ну и после того, как это все станет понятно, можно будет приступать к самим тестам.
Естественно, но именно так и не работает
ОК, что именно не работает в приведенном тобой коде?
А что ты там тестируешь я так и не понял
Тестируется setter проперти EnableRaisingEvents.
тем более что я пользую NUnit
Какая разница, в какой среде ты это тестируешь? NSubstitute - это библиотека для mock.
Не имеет значения, что я кидаю файл или каталог
Во первых ты не можешь кинуть файл. Кинуть можно обьект класса или базисный тип как параметр. Мы же внутри программного кода. Файл - это понятие файловой системы. В коде файловой системы нет, есть обьекты определенных классов с определенными параметрами. Вот это и тестируем
И там еще буфер в 4К по умолчанию.
где там? как твой код взаимодействует прямо или косвенно с буфером, что может произойти, какой ответ ты можешь получить?
А на кой мне эвент тестировать? Сколько раз его вызвал столько и придет, вроде как системная функция.
Не в этом дело. При определенных обстоятельствах в твоем коде может не дойти до вызова этой функции. Юниттест проверяет эти условия. Шаловливый коллега мог закоментировать вызов или заменить функцию другой. Юниттест защищает от этого. Но Юниттест не может дать результат "на этом компе результаты неудовлетворительные, компьютер медленный". В смысле может конечно, написать можно что угодно, но это будет неправильно. Юниттесты не снимают метрики.
Тестируется setter проперти EnableRaisingEvents.
А причем тогда файловая система?
System.IO.File.GetAttributes(path);
где могут быть проблемы в твоем коде и как смоделировать эти проблемы
А зачем их моделировать?
Сделаю я лучше пару временных тест каталогов и всё протестирую "наживую"
ОК, что именно не работает в приведенном тобой коде?
В приведенной версии, если я перемещаю каталог в директорию которая мониторится, возникает событие о создании объекта.
Мы же внутри программного кода
Не мы а Вы
Я говорил о реальном тесте, который мне нужен.
где там?
В FileSystemWatcher
A 4 KB buffer can track changes on approximately 80 files in a directory. Each event takes up 16 bytes in the buffer, plus enough bytes to store the name of the file, in Unicode (2 bytes per character), that the event occurred on.
Если дофига файлов накидаю, могу ничего и не получить. Так что можно долго и нудно моделировать и усё будет в порядке.
А зачем их моделировать?Сделаю я лучше пару временных тест каталогов и всё протестирую "наживую"
Это будет рукоблудство. Твой коллега взял твой код и запустил юниттесты - а они упали, потому что каталога нет. У тебя стоит билдсервер. Его дело строить приложение. Перед этим он прогоняет юниттесты. Тесты не прошли. А должны были, на билдсервере не должно быть точно воспроизведено окружение для запуска.
Если ты все делаешь на коленке, то ты можешь насиловать тесты как тебе угодно. Но если ты пишешь тесты напоказ или как учебное заданиe, то должен учитывать, что ты не знаешь, в каких условиях на фирме будут запушены тесты. И тестировать они должны правильно. Не то, что тебе хочется, а то, что можно и нужно. Для каждой цели свой инструмент.
Но Юниттест не может дать результат "на этом компе результаты неудовлетворительные
На так о чем я и говорю, что не нужны в данном случае юнит тесты, потому как все ситуации смоделировать невозможно.
Меня сейчас будущее не интересует, что кто то, что то, когда то сломает.
а они упали, потому что каталога нет
Так в тестах он и будет создаваться, всё с нуля, на "чистой системе".
Ну не вижу я никакого смысла делать море моделей и потом их настраивать. Приложение то показать и выбросить. Хотя и показывать то некому. Чисто для себя делаю.
Я говорил о реальном тесте, который мне нужен.
Мы. Потому что юниттест работает только и исключительно только внутри програмного кода. Если я неправ, то приведи пример обратного. Поэтому мы передаем в тест тестируемый обьект, вызываем тестируемую функцию и проверяем ресультаты. Тестируемая функция внутри кода работает исключительно с другими элементами кода, никогда не с файлами.
Так что можно долго и нудно моделировать и усё будет в порядке.
Именно. FileSystemWatcher управляет мониторингом файлов. Ты не можешь юниттестами проверять поведение этого класса, потому что ты ЗНАЕШь как он себя поведет. Зачем здесь юниттесты, которые будут запускаться автоматически при каждом коммите в репозиторий и при каждом построении приложения? FileSystemWatcher как работал максимум с 80 файлами так и будет это делать. Какая цель проверять
это на каждом компе, куда попадет програмный код? Заметь, не приложение будет запущено, а именно попадет програмный код. Билдсервер, компы коллеg
Так в тестах он и будет создаваться, всё с нуля, на "чистой системе".
А права у него есть "создавать"? А если в системе есть уже такой каталог? После окончания теста каталог будет снесен вместе с содержимым?
Приложение то показать и выбросить.
Вот именно. Это учебное приложение. Опустим, что тебя конкретно никто не тестирует. Но имхо, если делаешь учебное приложение, ты должен делать так, как надо. Потому что имхо запустить юниттесты для меня на внешний ресурс это концептуальная ошибка.Опасно. Может упасть в любой момент и твой коллега будет сидеть и думать, что он сломал в системе и почему у него üниттесты не идут.
А причем тогда файловая система?
System.IO.File.GetAttributes(path);
Ты привел кусок кода, написал:
Ну вот кусок кода для настройки. Вроде всё верно. А гад реагирует на копирование каталога.
я из твоих слов делаю вывод, что приведенный тобой код работает неправильно. К сожалению, ты в лучших традициях Murr'а не указал, что именно там не работает. Поэтому мне пришлось фантазировать. И я предположил, что когда ты начинаешь мониторить каталог:
//Start monitoring.
_watcher.EnableRaisingEvents = true;
а судя по твоему коду, мониторить ты начинаешь установив значение проперти EnableRaisingEvents в true, ты не различаешь файл и директорию. Очевидно, что если в _watcher был передан путь к директории, то должна быть сгенерирована ошибка. Именно это и проверяют тесты, которые я привел в качестве примера.
А зачем их моделировать?
Затем, что ты почему-то решил писать юнит-тесты.
Сделаю я лучше пару временных тест каталогов и всё протестирую "наживую"
Это сколько угодно. Почему ты тогда говоришь о юнит-тестах? Юнит-тесты - это совершенно определенная технология. Если хочешь тестировать все приложение, то можно использоваться BDD (например NBehave).
В приведенной версии, если я перемещаю каталог в директорию которая мониторится, возникает событие о создании объекта.
Код, где это происходит ты не приводил.
Если дофига файлов накидаю, могу ничего и не получить.
------
Тебе не нужно тестировать FileSystemWatcher.
Тебе нужно тестировать реакцию твоего приложения на то как он сработает при переполнении его очереди.
При какой-либо отсутствии реакции или отсустствии события ты все одно ничего не можешь сделать....
Вообще-то - указал - реагирует на копирование каталога
Б@*ть! Ошибка-то в чем? В том что сгенерировался эвент на каталог или в том, что был скопирован каталог? И где код, в котором происходит эта ошибка?
FileSystemWatcher.cs
А теперь просмотри топик и найти код из этого файла.
Ошибка-то в чем?
-----
Ошибка в том, что ватчер настроен на отслеживание создания файлов, а реагирует на них и на создание каталога.
В том что сгенерировался эвент на каталог или в том, что был скопирован каталог?
------
Тебе нужно поработать с FileSystemWatcher чтобы понимать возникающие проблемы.
Я, когда-то, считал что мне нужно мониторить некоторые изменения из студийного адд-она и потому его использовал - по-этому мне понятны проблемы Алекса. Самое смешное - тогда оказалось что мониторить ничего не надо...
А теперь просмотри топик и найти код из этого файла.
------
Зачем?
Ты спросил - Где именно возникает проблема? - Я дал тебе имя файла в котором находится этот код.
Файл - общедоступный. К нему, кстати, и тесты где-то были...
Ошибка в том, что ватчер настроен на отслеживание создания файлов, а реагирует на них и на создание каталога.
Т.е. баг в FileSystemWatcher?
Тебе нужно поработать с FileSystemWatcher чтобы понимать возникающие проблемы.
Нафига мне с ним работать?
Зачем?
Затем, что юнит-тестами покрывают СВОЙ код, чтобы быть уверенными в том, он удовлетворяет требованиям.
Т.е. баг в FileSystemWatcher?
-----
Скорее - фича. Надо в доках смотреть...
Нафига мне с ним работать?
-----
Чтобы не понимать об чем написано.
Затем, что юнит-тестами покрывают СВОЙ код, чтобы быть уверенными в том, он удовлетворяет требованиям.
-----
Угу...
Вот только для теста нужен мок, который должен отработать... как оригинальный код.
А чтобы его слепить - надо понимать/знать чего ожидать, включая ошибки и фичи...
Скорее - фича. Надо в доках смотреть...
Ну т.е. тестировать это не надо ;)
Вот только для теста нужен мок, который должен отработать... как оригинальный код.
Не должен.
А чтобы его слепить - надо понимать/знать чего ожидать, включая ошибки и фичи...
Ну, как ты сам говоришь, это надо смотреть в доках.
Тестируемая функция внутри кода работает исключительно с другими элементами кода, никогда не с файлами
Вполне может быть, "клеан юнит тест" правил я еще не учил. Тогда мне требуется что то другое, потому как большинство действий делается на уровне файловой системы и моделировать их смысла нет.
При этом, почти уверен что простая модель будет работать без проблем.
потому что ты ЗНАЕШь как он себя поведет
В том то и дело что не знаю, догадываться могу, но не знаю, как он будете себя вести во всех ситуациях. На сетевом диске например.
которые будут запускаться автоматически при каждом коммите
А отчего все должны запускаться при каждом коммите? Даже и на работе у нас было разделение, на ежедневные и после коммитные.
FileSystemWatcher как работал максимум с 80 файлами так и будет это делать
А я этого кстати, еще и не знаю, не проверял. Да и неизвестно как он себя поведет если время "выхода из эвента" будет долгим.
Ну и у меня на каждое сообщение запускался новый треад, а что будет когда они закончатся? Сейчас уже на ConcurrentQueue переделал с одним треадом
А если в системе есть уже такой каталог?
Маловероятно для случайно сгенерированного имени, но можно и еще раз сгенерить. Права должны дать.
После окончания теста каталог будет снесен вместе с содержимым?
Безусловно и свободное место будет проверяться. Корзина правда не будет чистится.
если делаешь учебное приложение, ты должен делать так, как надо.
Согласен, но в данном случае меня "поджимают сроки". Зачем мне инвестировать время в приложение которое идет на помойку.
Я свои юнит теста для парсера еще не окончил.
твой коллега будет сидеть и думать, что он сломал в системе
Ничего он думать не будет, у него будет сообщение с описанием проблемы. Типа "не могу создать тестовый каталог".
а не указал, что именно там не работает.
Может быть не очень подробно описал, но мне казалось что вполне достаточно.
https://foren.germany.ru/showmessage.pl?Number=37855570&Bo...
А гад реагирует на копирование каталога. _watcher.IncludeSubdirectories = false;
То бишь IncludeSubdirectories = false, из описания можно понять что этого достаточно для того чтобы извещение о добавлении нового каталога не приходило.
А оно приходит.
Очевидно, что если в _watcher был передан путь к директории
Так ему и нужен путь какую директорию мониторить.
Именно это и проверяют тесты, которые я привел в качестве примера.
Но так они это проверяют на основе знаний о файловой системе, а именно от этого хотелось вроде уйти.
Затем, что ты почему-то решил писать юнит-тесты.
Это не я решил, для этой проги я бы их не делал. Но в задании было так.
NBehave
ну вот что то новое узнал
Код, где это происходит ты не приводил.
какой то класс был полностью, но и тех строчек что было вполне достаточно, там отсутствует только обработчик извещения, который просто транслирует его наверх.
а не указал, что именно там не работает.
Может быть не очень подробно описал, но мне казалось что вполне достаточно.
Из твоего описания было не понятно, что именно ты хочешь протестировать юнит-тестами. Собственно говоря, ты так до сиз пор и не ответил на этот вопрос. А значит рано еще приступать к написанию каких-либо юнит-тестов.
К сожалению, многие пренебрегают ответом на вопрос "что я хочу протестировать?". И пытаются фигачить тесты с установкой "чем больше, тем лучше" или "нам сказали писать тесты, мы и пишем".
Но так они это проверяют на основе знаний о файловой системе, а именно от этого хотелось вроде уйти.
Ну после нескольких сообщений я наконец понял, что FileSystemWatcher - это некий third party объект, а значит он работает правильно и тестировать его не надо. А ошибка у тебя была в инициализации.
Но если мы вернемся к тестированию, то значит тестировать тебе надо класс DirectoryWatcher, а для FileSystemWatcher сделать обертку. После этого ты просто сможешь эвент Created и проверять код хэндлера Watcher_Created. Никакие манипуляции с файловой системой для этого не будут нужны :)
какой то класс был полностью, но и тех строчек что было вполне достаточно, там отсутствует только обработчик извещения, который просто транслирует его наверх.
Те строчки, что ты привел - это просто инициализация. Впрочем, на инициализацию тоже можно легко написать тест :)
Собственно говоря, ты так до сиз пор и не ответил на этот вопрос
И не думаю что когда либо отвечу, в разрезе конкретно моего кода. Нет там никакой особой логики.
Нажали кнопу - появился диалог, взяли имя каталога для наблюдения
Нажали кнопу начали наблюдать за каталогом.
Кинули туда чего-то, пришло извещение, сделали какие то действия.
Всё самое интересное происходит на уровне файловой системы и во взаимодействии с кодом.
А ошибка у тебя была в инициализации.
Ну так именно это и хотелось проверить.
После этого ты просто сможешь эвент Created и проверять код хэндлера Watcher_Created.
Я и без этого могу проверять код хэндлера Watcher_Created ---_mainWorker.WorkOnNewItem(e);
Но там опять таки манипуляции с файлами, которые опять нужно как то имитировать. И имитация будет точно уж неполной.
Впрочем, на инициализацию тоже можно легко написать тест
ну и как это сделать не трогая файловую систему?
Ты потом сам написал, что один параметр не установил
Ну так это я нашел только после реального теста с файловой системой.
Это всё к тому что не нужно тестировать системные функции - они и так правильно работают.
Как бы я с виртуальными тестами не извращался никогда бы не нашел.
-----
Да ну? И как же ты будешь эмулировать результат переполнения буфера если об этом даже не в курсе?
это надо смотреть в доках.
-----
Ну так смотри.
А то получается ни доkи не посмотрел, ни практики не поимел, но об том КАК - вполне готов говорить... причем начиная с того что тебе непонятны описанные проблемы...
достаточно для того чтобы извещение о добавлении нового каталога не приходило.
-----
Не-а... это мониторинг субфолдеров. Т.е. если есть вложенные папки - будет-не-будет трекировать в них тоже...
Удобно - задал "С:\\" с подкаталогами и весь диск мониторишь...
В том то и дело что не знаю, догадываться могу, но не знаю, как он будете себя вести во всех ситуациях. На сетевом диске например.
Ты не можешь выяснять это юниттестами.
А отчего все должны запускаться при каждом коммите? Даже и на работе у нас было разделение, на ежедневные и после коммитные.
Ладно, при катгдом бильде. НО это неважно, политика фирмы, ты же должен расчитывать на то, что тесты будут долбиться постоянно много раз и в разных условиях, причем часто там, где конкретное исследование твоего мониторa нафиг не впало. Еще раз - коллега скачает код, код рухнет на бильде и именно коллега будет трахаться, не понимая, как его изменения могли привести к такому повреждению кода, что перестали идти юниттесты.
Ничего он думать не будет, у него будет сообщение с описанием проблемы. Типа "не могу создать тестовый каталог".
Ты походу никому не запарывал юниттесты Результат - злоба за потерянное время.
Маловероятно для
Значит возможно. Значит нельзя.
После окончания теста каталог будет снесен вместе с содержимым? Безусловно и свободное место будет проверяться.
Представь, что у коллеги есть такой же каталог и там дорогие его сердцу фотографии шефа. Он запускает тесты, все прошло на ура и через пару дней он узнает, что ТВОЙ код что то удалил на ЕГО компе. Без запросов.
Зачем мне инвестировать время в приложение которое идет на помойку.
Точно затем же, зачем мы все это здесь обсуждаем. Какова цель создание приложения, которое идет на помойку? Научится делать правильно с учетом возможных последствий. Представь себе, что ты сдал униттест как учебное приложение во время собеседования. А там косяк...
Да ну? И как же ты будешь эмулировать результат переполнения буфера если об этом даже не в курсе?
Мок не должен работать как оригинал. Более того, мок вообще не должен работать. Он должен уметь симулировать ответы оригинала. Нельзя протестовать юниттестами то, о чем не имеешь представления. Можно проверить свой код на устойчивость к общим ошибкам, но не к ошибке, о существовании которой ты не подозреваешь и которая возникает только в определенных условиях. Нельзя надеятся юниттестами что то отловить, о чем не подозреваешь - они предназначены для СТРОГО определенных целей и определенных программистом.
А то получается ни доки не посмотрел, ни практики не поимел, но об том КАК - вполне готов говорить... причем начиная с того что тебе непонятны описанные проблемы...
Проблему Программист понял правильно - недостаточная абстракция при тестировании юниттестами, попытка применить юниттест для изучения работы системы целиком. Тесты для системной функции нафиг никому не нужны.Более того - они сами источник ошибок и потери времени.
Ну так это я нашел только после реального теста с файловой системой.
Ну если ты чтение мануалов хочешь заменить тестами, то у тебя долгий и трудный путь :)
FileSystemWatcher.NotifyFilter:
The default is the bitwise OR combination of LastWrite, FileName, and DirectoryName.
Это всё к тому что не нужно тестировать системные функции - они и так правильно работают.
Во-первых, тебе это говорили с самого начала.
Во-вторых, это правило распространяется не только на системные функции, но и вообще на все third party объекты. При этом это не просто объекты от посторонних производителей. При создании юнит-теста все внешние связи принимаются как работающие без ошибок. Даже если это "соседний" класс и тойже самой сборки, что и твой unit under test.
Как бы я с виртуальными тестами не извращался никогда бы не нашел.
Это да. Потому что искать надо было в мануалах. Тесты существуют не для поиска документации.
Да ну? И как же ты будешь эмулировать результат переполнения буфера если об этом даже не в курсе?
Не понимаю, в чем проблема?
Ну так смотри.А то получается ни доkи не посмотрел, ни практики не поимел, но об том КАК - вполне готов говорить... причем начиная с того что тебе непонятны описанные проблемы...
AlexNek спрашивал как написать тест. При этом он не в состоянии ни описать проблему и ни сформулировать, что же он хочет протестировать. В таких условиях приходится фантазировать. А в результате выясняется, что он просто не прочитал мануал.
Не-а... это мониторинг субфолдеров
Понимание данного аспекта приходит позже
А поначалу кажется что всё по другому - "Gets or sets a value indicating whether subdirectories within the specified path should be monitored."
Если каталоги не мониторятся, то так вроде и нужно.
Ты не можешь выяснять это юниттестами.
Ну а чем тогда?
Меня сопровождение и прочее как-то совершенно не интересует в данное время.
Мне нужна какая то помощь во время разработки.
Да и на будущее делать эмулятор файловой системы совсем не хочется.
что у коллеги есть такой же каталог
Имя достаточно специфическое, да и можно документацию написать.
Это будет проще чем городить эмулятор файловой системы. Тем более что простых врапперов будет недостаточно.
Вот как раз сейчас новая проблема. Все по частям работает замечательно - а совместно фигвам. Чего то опять не учёл.
Научится делать правильно с учетом возможных последствий.
Ну если по теории нужно делать эмулятор и это будет правильно, то я не вижу когда данный путь будет приемлен. Затраты и результат просто несопоставимы.
Ну если ты чтение мануалов хочешь заменить тестами
Это всё хорошо читать когда нашел проблему и ее решение.
При создании юнит-теста все внешние связи принимаются как работающие без ошибок.
тогда получается что если мы принимаем данные от какого-то устройства, то они должны приходить без ошибок?
Да и на будущее делать эмулятор файловой системы совсем не хочется.
Mock-Object - это не эмулятор файловой системы :)
Это всё хорошо читать когда нашел проблему и ее решение.
Слушай, ну ведь дело-то не в этом. Дело в том, что ты не можешь сформулировать запрос.
В конце-концов, даже если бы не было проперти NotifyFilter, код DirectoryWatcher'а все равно можно сделать рабочим. Главное идентифицировать проблему. Ты этого не сделал. И тесты тут не при чем.
тогда получается что если мы принимаем данные от какого-то устройства, то они должны приходить без ошибок?
Нет. Есть разница межу "данные не имеют ошибок" и "компонента работает без ошибок".
Собственно говоря, даже если компонента содердит какие-то ошибки, ты все равно должен исходить из того, что компонента работает правильно.
Т.е. баг - это фича, с которой тебе надо жить и найти пути обхода. Т.к. внешнюю компоненту ты все равно не сможешь изменить.
Меня сопровождение и прочее как-то совершенно не интересует в данное время.Мне нужна какая то помощь во время разработки.
AlexNek, ты определись, что тебе нужно. Если тебе нужно сделать законченное(пусть и учебное) классическое приложение с законченным циклом разработки, то нужно делать правильно. Если тебе нужно решить конкретную проблему(быстро выяснить, как что то работает), то неважно, какие средства ты у себя локально используешь. Они просто не должны попадать в общий репозиторий. Разумеется юниттесты удобны для запуска куска кода.
Имя достаточно специфическое, да и можно документацию написать.Это будет проще чем городить эмулятор файловой системы.
Нет. Сорри, нагадить в лифте проще, чем до туалета добежать. Но есть вещи, которые делать ну нежелательно. Чел никакую документацию читать не будет, просто потому что ему твой модуль нафихг не впал. На крупной фирме с сотней программистов и кучей отделов никому не интересно, что ты там наваял и что нужно на своем компе организовать, что бы все стартануло.Если чел с опытом, он увидит, что чужие тесты не идут и скачает с репозитория версию без своих изменений. Втиснет ее в среду разработки. Стартанет тесты. Увидит, что тесты не идут. И потребует привести тесты в порядок, что бы они запускались на любом компе, ибо без этого нельзя. Или в настройках проги будет сетевой каталог, которого просто с билдсервера не видно и когда ВСЯ фирма не сможет больше мержить, потому что внезапно перестали идти тесты и шеф будет искать виноватого в паре-сотне часов простоя - тогда будет весело.
Затраты и результат просто несопоставимы.
Просто нужно отказываться от идеии быстро-быстро сделать все на коленке. В принципе я могу представить себе ситуацию, когда расходы на юниттесты делают весь модуль нерентабельным - слишком сложно тестировать. Но в твоем случае (я не программирую на шарпе) на яве это элементарно.Проблема просто понять, где и для чего нужны юниттестy
тогда получается что если мы принимаем данные от какого-то устройства, то они должны приходить без ошибок?
Ошибка - это неожиданная и не предусмотренная реакция кода на ситуацию. В шарпе ексцепшионы есть? так вот выброс исключения "переполнение буфера" - это не ошибка. Это ожидаемая реакция на черезвычайную ситуацию.Ошибка - это типа когда ты читаешь имя файла и если там есть пробел, то вдруг вылетает нульпойнтерексцепшион. И это никто не ожидает и так быть не должно.
Странный ты.
Ты понимаешь, что в данном случае проблема не в мануале?
Проблема в том, что AlexNek захотел использовать некий инструмент и при этом не понял, для чего этот инструмент нужен и как им пользоваться.
Ну это как если бы тебе дали зажигалку и сказали, "этой штукой разжигают огонь и можно круто пожарить шашлыки". А ты такой взял эту зажигалку, сел в машину и спалил ее к чертям, т.к. там тоже есть "зажигание" и вообще машина с ДВС едет за счет горения.
ты определись, что тебе нужно.
На каждом шаге разное
Для начала мне нужно рабочее приложение.
Затем среда для его тестирования.
А делать что то практически бесполезное смысла не вижу. Даже если я напишу все на заглушках, то оно будет только тестировать простейшую логику приложения и позволит с гордостью сказать вот у нас есть правильные юнит тесты.
А прога в итоге и не работает всегда правильно.
Если бы у приложения была бы какая-то нетривиальная логика, то еще какой то смысл был бы. А так, просто последовательность шагов: сжать и переместить.
Но всё завязано именно на манипуляциях с файловой системой, которую трогать низзя.
На крупной фирме с сотней программистов
Сорри, с такими еще не сталкивался и думаю что уже и не получится. Чтобы целая сотня над чем то одним работала.
Но в твоем случае (я не программирую на шарпе) на яве это элементарно
Не вижу особой разницы в языках, но и элементарности тоже не вижу.
и при этом не понял
------
Ну так разъяснил бы. На доки не кивай - там описание с проблеммами.
А то Я эту фигню пытался использовать года 4 назад и уже подзабыл.
Что вспоминал - пояснял.
Вот про поведение буфера - не помню - никогда не сталкивался...
просто не хотите понимать.
мы не первые и не последние
Recently there’s been some discussion in the community about a long-held belief regarding unit tests: A unit test should not touch the filesystem.
https://www.leadingagile.com/2017/12/should-unit-tests-tou...
Ага. Первой беды не только в России, по всему миру на 100 лет вперёд припасено. Автора этого бложика явно припасли с запасом.
Вам уже неоднократно писали что юнит-тесты проверяют только ваш код. Не процессор, не операционную систему, не файловую систему, не библиотеку по распаковке файлов. А ваш код, который всё это богатство использует.
Если вы хотите тестировать стороннюю библиотеку - пожалуйста, ради бога. Но называйте эти тесты как минимум "интеграционными". Хотите протестировать скорость выполнения? Нет преграды патриотам. Но не называйте это юнит-тестом. Назовите "нагрузочным тестом".
Понимаете?
Да один фиг как назвать, главное что бы был польза.
Нет. Как раз очень важно. Юниттест это не просто технология, позволяющая запустить кусок кода без создания полного контекста приложения. Это еще и технология, которая применяется в определенных местах. Строго определенных. Именно поэтому юниттест с определенным кодом вызавает недоумение - он просто не лезет в эти самые места. То ты и не собираешься его туда пихать. У тебя другие цели.В результате мы перепинаемся уже под сотню постов на ровном месте.
Вопрос определениj и основанного на них понимания.
Да один фиг как назвать, главное что бы был польза.
Садись, два! (c)
- Тема: велосипед, чтобы ездить на работу
- А в чём проблема?
- Мне до работы 150 км в одну сторону
- Тогда, наверное, нужен не велосипед а машина? Или на велосипеде доезжать только до вокзала?
- Какое гавно эти ваши велосипеды, а все рассказывают что только на них надо ездить
- Так может всё же нужна машина?
- Один фиг как называть, лишь бы на работу доехать.
Звучит глуповато, не?
Может всё же определиться для начала что же тестировать надо, а потом выбирать чем и как?
Может всё же определиться для начала что же тестировать надо
По историческим причинам было наоборот
Согласно условию задачи требовались юнит тесты. Но как оказалось, они смысла особого не имеют в данном случае.
Тоже самое что и с tray application. Данный тип приложения совершенно бессмыслен в данном случае, а что бы из нормального сделать трей, нужно всю инициализацию и обработку "не отловленных" ошибок сделать по другому.
Для "поиграться" всё слишком много по времени. По крайней мере, нашел проблемы и чему то научился.
Мне бы лучше приложение из Azure на свой сервер перекинуть, хоть абонплату сэкономил бы.
Согласно условию задачи требовались юнит тесты. Но как оказалось, они смысла особого не имеют в данном случае.
Из моего опыта последних 10 лет - юнит тесты нужны всегда если проект должен жить дольше 6 месяцев. И смысл в них есть. Даже для геттера надо писать тест. Потому что уже не раз и не два были очепятки. А потом - ой, а чего это мы вместо 16 потоков используем 62342? А перепутали. Закопипейстелись. При инициализации менеджера uid пользователя из параметра конструктора записали и в поле uid и в поле maxThreads.
А чтобы найти эту примитивную ошибку, тратишь не минуту и не час. А потом еще и задеплой всё заново.
если проект должен жить дольше 6 месяцев.
А если проект будет жить 0 часов, 0 минут?
Для того чтобы написать ЮТ согласно академическим канонам, нужно перелопатить всё приложение, написать штуки три тестовых заглушки, а потом еще думать как смоделировать возможные ошибки.
При этом для разработки они мне почти бессмысленны.
Вот в другом проекте, где дофига логики, там без них и шагу ступить невозможно.
А если проект будет жить 0 часов, 0 минут?
То даже код проекта можно не писать.
Для того чтобы написать ЮТ согласно академическим канонам, нужно перелопатить всё приложение, написать штуки три тестовых заглушки, а потом еще думать как смоделировать возможные ошибки.
Сложность написания юнит-тестов - хороший индикатор дерьмовости кода.
Как именно делать моки - дело вкуса. Сегодня глупо не использовать для этого библиотеки. Я честно говоря не знаю что сейчас для шарпа есть, лет 5 назад даже easymock.net был, не знаю, может и жив ещё.
Главное чтобы с минимальными усилиями было получить реализацию интерфейса ICompressor (пусть он так называется), у которой мы определяем ТОЛЬКО метод CompressFile. А все остальные 20 методов нам глубоко не интересны. И для разных тестов определяем поведение этого метода:
1. что-то нам нужное вернёт (строку, код состояния, мок объекта)
2. вернет что-то неправильное (пустую строку, неизвестный код, нуль)
3. бросит исключение
И проверяем что наш код всё это правильно переварит.
Ну вот вроде популярная либа Moq
https://habr.com/ru/post/150859/
Всё что она может сэкономить - это не писать заглушку.
Но усложнять код все равно придётся, так как и компрессор и мувер нужно передать извне в тестируемый класс. А еще есть и третий класс - обозреватель каталога.
То бишь в "главный класс" нужно передать минимум 3 совершенно не нужных параметра, а с экспортом и 4. Соответственно и количество лишних интерфейсов возрастает.
В общем, KISS - пошел нафиг.
Ну и как проверить конкретные имплементации интерфейсов вопрос остается открытым.
Например, как проверить, что когда компрессор создает файл, то этот файл будет игнорироваться обозревателем каталога. Хотя, даже как это проверить можно и что то придумать, а вот как до этого "дойти" в тестовой системе не имею представления.
То бишь в "главный класс" нужно передать минимум 3 совершенно не нужных параметра, а с экспортом и 4. Соответственно и количество лишних интерфейсов возрастает.
В общем, KISS - пошел нафиг.
Насчёт ненужных я бы поспорил. И насчёт нарушения KISS. Если компрессор и мувер не передаются снаружи значит что? Значит класс такой "умный" что сам знает как их сделать. Во-первых это сложнее чем получить их снаружи. Во-вторых это а. дополнительная ответственность и б. нарушение open-close. Аж две буквы из SOlid поломали.
Аж две буквы из SOlid поломали.
У меня есть одна проблема - не люблю слепо следовать догмам. Не люблю делать универсальных монстров и стрелять из пушки по воробьям.
Если для экспорта еще как то можно представить себе изменения, то для компрессора и мувера - довольно сложно. Вполне достаточно того, что они вынесены в отдельный класс.
Ну и делать конструкторы вьювмоделей с параметрами для ВПФа, тоже не очень хорошо.
Тем более, что прога не идет в промышленную эксплуатацию на многие годы.
Ну и делать конструкторы вьювмоделей с параметрами для ВПФа, тоже не очень хорошо.
Почему это?
Тем более, что прога не идет в промышленную эксплуатацию на многие годы.
Насколько я понимаю, в твоем случае речь идет о тестовом задании. Так вот при выполнении тестового задания от тебя хотят увидеть а) понимание технологии юнит-тестирования и б) красивое решение, желательно по SOLID.
Почему это?
Добавь в подобную конструкцию еще параметры
<Window.DataContext> <local:CustomViewModel /> </Window.DataContext> ... <Window.Resources> <local:MyViewModel x:Key="MyViewModel"/> </Window.Resources> <Grid DataContext="{StaticResource MyViewModel}"> </Grid> <pre>
от тебя хотят увидеть
Скорее услышать. Времени то челу дали всего час. Кто то за час всё сделает?
Добавь в подобную конструкцию еще параметры
Ну просто инициализируешь ViewModel не в XAML, а в code behind, а именно:
InitializeComponent(); DataContext = new CustomViewModel(what-ever);
не вижу в этом никакой проблемы.
Скорее услышать. Времени то челу дали всего час. Кто то за час всё сделает?
Час конечно маловато. Но подход увидеть вполне можно.
Ну просто инициализируешь ViewModel не в XAML
Получается что следуя одному принципу мы закрываем другие.
Не могу уже вспомнить конкретную проблему, но пришлось специально убирать все параметры из конструктора. Не всегда можно code behind пользовать
Но подход увидеть вполне можно.
Ну сделай эксперимент, что получится сделать за час. Даже на своём компе. Главное - не копипастить
Мне вот тоже интересно стало, правда забыл глянуть что за час сделал. Но я и не собирался на скорость, что то писать - совершенно бессмысленное занятие.
Получается что следуя одному принципу мы закрываем другие.
Не понял, что мы закрываем?
Не могу уже вспомнить конкретную проблему, но пришлось специально убирать все параметры из конструктора. Не всегда можно code behind пользовать
Не встречал еще ситуации, когда нет code behind.
Если у тебя есть элегантный способ передать настройки во ViewModel, то было бы интересно посмотреть на этот способ. А то я эля таких ситуаций использую параметры контруктора :)
Ну сделай эксперимент, что получится сделать за час.
Честно говоря, мне лень :) Думаю, что в течении дня я бы сделал то задание.
То бишь в "главный класс" нужно передать минимум 3 совершенно не нужных параметра, а с экспортом и 4. Соответственно и количество лишних интерфейсов возрастает.
Не надо. Технологии WhiteBox, инектирование, подмена переменных класса во время выполнения. Это можно делать даже для приватных переменных. Но переменные можно делать наследуемыми и тестировать наследников класса с дополнительными сеттерами.Есть много способов внедрить мок вместо реального обьекта. А вот если нельзя, значит в классе проблемы. И функциональный и инитиализатионных код свален в одну кучу.
Не понял, что мы закрываем?
Ну хотя бы инициализацию из ХАМЛа. Как передать во вьюв-модель из ХАМЛа что-то кроме строки я не знаю.
Не встречал еще ситуации, когда нет code behind.
Тоже было до поры до времени, пока более сложный UI не понадобился.
Если у тебя есть элегантный способ передать настройки во ViewModel
Они просто идут вторым шагом, через сервис например или через сообщения.
Думаю, что в течении дня я бы сделал
Я тоже так думал, но не получилось. Там проблем больше чем вначале думаешь.
Но возьми даже 1/8 часть готового приложения, что это будет в итоге?
Во-вторых это а. дополнительная ответственность
Вот другая проблема есть, решение которой мне совершенно не нравиться, но пока не могу придумать лучше.
Есть у меня сообщение о добавлении файла в каталог. Его нужно обработать как можно быстрее, поэтому сообщение просто записывается в очередь.
Также есть отдельный поток который извлекает сообщения из очереди и затем уже делает с ними нужные операции, которые могут быть достаточно долгими.
Каждая операция реализована как вызов функции из дополнительного класса. Но вот эти все вызовы расположены в одном месте и они все разные.
С одной стороны это файловый операции, а с другой стороны, добавление новых элементов в UI и их сохранение.
Хотелось, хотя бы отделить файловые операции и UI, только как тогда информировать нужный UI элемент об ошибке.
Ну так и DI можно также делать
Если речь идёт о DI Container/Frameworks, то я их пока не переношу.
Когда всё приложение так построено, разобраться в его работе очень сложно.
Так поставил точку останова в конструкторе и знаешь кто и откуда вызвал. А с контейнером поди еще найди как эта инстасе получается т откуда пришел вызов.
Ты как-то не так понимаешь DI
Может быть. У меня есть просто различия, когда нужно, а когда нет. А не только - исключительно всё на интерфейсах внутри, а снаружи вся имплементация.
Ну зачем мне ещё добавлять "интерфейс компрессии файла" и выводить его наружу? Только для того, что может быть когда то, кто то захочет его имплементировать по другому, оставив при этом и старую версию.
Хочешь менять - меняй, всё в отдельном классе. Когда понадобится вторая имплементация, можно будет сделать, но никак не раньше того, чем вероятно может понадобится или понадобилось.
В данном случае - вероятность изменений практически нулевая.
Ну зачем мне ещё добавлять "интерфейс компрессии файла" и выводить его наружу?
Ну тут есть несколько моментов:
1) для того, чтобы код был тестируемым.
2) чтобы класс отвечал только за то, чем он занимается. И не занимался 2-мя, 3-мя и более вещами. Single Responsibility.
3) расширяемость
У меня есть просто различия, когда нужно, а когда нет.
Ну просто для тебя "нужно" - это только расширяемость :) Но на самом деле расширяемость - это просто побочная плюшка :D
1) для того, чтобы код был тестируемым.
Вот именно с этим у меня и наблюдаются проблемы.
Я не хочу исключительно только для тестирования добавлять море вещей которые мне совсем не нужны.
2) чтобы класс отвечал только за то, чем он занимается.
А класс и не занимается сжатием, за это отвечает другой класс.
Если кто-то захочет изменить сжатие, то он будет это менять в другом месте.
3) расширяемость
Зачем предусматривать расширяемость, когда эта расширяемость не понадобится.
Ну зачем мне автомобилю делать складываемые крылья или цеплять замаскированный парашют, на тот случай если он вдруг упадет в ущелье?
Event-ы наше всё!
И чем они мне помогут? Ну выдам эвент с ошибкой, а ключа то у меня нет к какой конкретно записи относится ошибка. Уникальный ключ как-то делать?
Записывать все данные может быть и можно. Но для этого у меня и так внешний Action есть.
Я не хочу исключительно только для тестирования добавлять море вещей которые мне совсем не нужны.
Ну нет проблем :) Просто в таком случае ты пишешь код, который нельзя протестировать юнит-тестами. Есть и другие способы протестировать код :)
А класс и не занимается сжатием, за это отвечает другой класс.
Если кто-то захочет изменить сжатие, то он будет это менять в другом месте.
Твой класс как минимум создает объект, который занимается сжатием и конфигурирует/инициализирует этот объект.
Зачем предусматривать расширяемость, когда эта расширяемость не понадобится.
Затем, что это приятный бонус, который ты получаешь совершенно бесплатно, если проектируешь софт по определенным правилам :)
Ну зачем мне автомобилю делать складываемые крылья или цеплять замаскированный парашют, на тот случай если он вдруг упадет в ущелье?
В автомоболе можно поставить вместо приборной дочки полноценный дисплей и тогда помимо изображения любой технической информации о состоянии машины, можно еще показывать навигационную систему или даже киношки. При этом телевизор получается без каких-либо дополнительных затрат.
Твой класс как минимум создает объект
Ну и что, кто то всё равно должен его создать. Всё что мы теряем - это динамическая замена. Которая относится к разряду ненужных.
если проектируешь софт по определенным правилам
правила и так есть, только не следует понимать их буквально.
То бишь, нужно мне в классе, допустим, 10 операций, то всех их абсолютно обуть в классы и интерфейсы и инициализировать строго снаружи.
В автомобиле можно поставить вместо приборной доски полноценный дисплей
Можно, но вот парашют и крылья считаешь, что не нужно?
Вот у меня такое же деление и есть, когда нужно - то делаем, когда не нужно - то нет.
А вот лет 50 так назад, ты бы тоже считал, что можно поставить туды "полноценный дисплей"?
С другой стороны, у меня в ентом авто приборная доска и управление работает чисто механически. И что бы переделать всё в цифру нужно затратить много времени и денег.
То бишь, дырки для крепления сделать еще могу, а вот подсоединить текущие приборы через разъем ну никак не получится.
Вообще то, как оказалось, есть более приемлемый метод для меня.
достаточно вместо
compressor.Compress(fileName);
написать
CompressFile(fileName);
virtual void CompressFile(string fileName)
{
compressor.Compress(fileName);
}
А затем уже замокать эту виртуальную функцию.
Ну вот если устройство мне посылает дату 30.02.2021 - это как класифицировать?
Сорры. Только сейчас заметил
Это особенность устройства. Программист писал насчет фичи, но общий принцип такой - устройство может посылать инфу в определенном кодирунге, на китайском языке, в странном формате. Если такой вывод использовать нельзя, то и устройство использовать нельзя. Если можно с последующей обработкой. то нужен код обработки. Но долбить эту особенность устройства юниттестами (долбить - потому что юниттесты запускаются автоматически регуларно, проверяя код) нет смысла - особенность устройства извeстна и не изменится. А вот собственный код обработки особенности можно и нужно
особенность устройства известна и не изменится
-----
Хи-хи...
Из того что помню.
Три завода, три инсталяции Оракла.
Каждая инсталяция - мало того что другой версии, так еще и со своей локалью.
Соответственно - формат даты и времени - разный, порядок сравнения и сортировок - тоже разный.
Код - общий для всех баз...
нет смысла
-----
Оно, вообще-то, программируемое.
Хи-хи... Из того что помню.Три завода, три инсталяции Оракла.Каждая инсталяция - мало того что другой версии, так еще и со своей локалью.Соответственно - формат даты и времени - разный, порядок сравнения и сортировок - тоже разный.Код - общий для всех баз..
Ты реально не понимаешь, что нет нужды тестировать порядок сравнения и сортировку в Оракле? Или просто прикидываешься?
Если такой вывод использовать нельзя, то и устройство использовать нельзя.
вывод использовать нельзя, но вот устройство нужно.
Это как раз и тестирует "мой" код - он не должен обваливаться если даже устройство пошлет что то неправильное.
Так что тесты нужны, хоть часть будет юнит тестами, а часть интеграцион тестами.
особенность устройства извeстна и не изменится
никакой документированной особенности устройства доверять нельзя
Всё нужно проверять. Пару раз железячников на этом и поймали.
Каждая инсталяция - мало того что другой версии, так еще и со своей локалью.
Как часто у одной инсталляции менялись свойства?
Оно, вообще-то, программируемое.
Ты хотел сказать конфигурируемое. Програмируемое - это дата 31.02.2021. Напрограмировали
Проблема конфигурируемых внешних систем в том, что свою реализацию пишут под конкретную конфигурацию(как правило собственная реализация тоже конфигурируема). Проверить все это невозможно даже в принципе. Система сконфигурирована под джейсон, а пришел хмл. Система написана под определенный Трансферобьект, а пришел совсем другой обьект или вообще стринг.
Поэтому пока система бегает, считают, что внешняя часть тоже неизменяема. Можно ораклувскую инстанцию вообще на другой сервер перекинуть и какой смысл что то там тестировать. Понятно, что приложение без базы данных не стартанет и если настройки изменить, то может эту самую базу вообще не найти.
Потом если у инсталляции установили китайскую локаль, то значит так надо было. Не думаю, что имеет смысл в приложении опрашивать текущую локаль базы данных. Я даже не заню, кто то это делает? Просто настраивают систему (прога+база) и это эта связка до следующей настройки считается неизменяемоj
вывод использовать нельзя, но вот устройство нужно.
------
Ну так понятно что деваисе надо мокать... вот чего аппоненты не желают понять - надо знать какие сюрпризы может дать деваисе и в доках оно не описано - надо дрючить девайсе из тестов пока не убедишься что собрал всю коллекцию проблеm...
Как часто у одной инсталляции менялись свойства?
------
А какая разница?
Я не контролирую сервера - может поменяться в любой момент и без уведомления.
То, что это не декаки с момента установки ситуацию никак не меняет.
Проверить все это невозможно даже в принципе.
-----
Ну наконец-то... правда пока не вижу понимания того что проверить можно только то об чем знаешь...
значит так надо было.
------
Да ну?
Мне вот всегда казалось, что это от непонимания того, что от этого что-то зависит.
По крайней мере в рамках одного предприятия.
Не думаю, что имеет смысл в приложении опрашивать текущую локаль базы данных.
------
Т.е. принимается как норма, что как только в запросе требуется фильтрация по дате, то приложение дожно упасть? Ну или выдать какую-нибудь чушь...
Не думаю, что имеет смысл в приложении опрашивать текущую локаль базы данных.
------
Еще раз.
Автоматизированное рабочее место.
Одна инсталяция программы.
Работает с тремя различными серверами, каждый из которых имеет свой диалект СКЛ и другую локаль.
Я чего - должен бегать туда каждый раз как девочке приспичит что-то сделать на другом серваке?
девайс не надо, только приложение
------
Присылали мне как-то файлик для импорта.
Без документации на формат - только ссылка на то, что он в каком-то внутреннем стандарте третьей стороны - они ничего другого экспортировать не умели. Готового редера - не было.
Внутри только дат было три разных формата, причем один из них вводился текстом в ручную...
Так будем тестить приложение или будем дрючить источник?
ЕМНИП Datetime - это просто число и локаль там по большому счету не нужна. А для того, чтобы безошибочно конвертнуть строку в DateTime можно использовать функцию CONVERT и передавать в ней дату в любом удобном и при этом заранее изместном виде :)
Подозреваю, что Murr как обычно простелил себе колено :)
это просто число
------
Вообще-то, в контексте СКЛ это будет строка в определенном формате.
можно использовать функцию CONVERT
------
Можно.
Но можно упереться в ограничение на длинну выражения в IN...
И, кстати, КОНВЕРТ тормозит довольно прилично... хотя основное - он там вообще не нужен, если не требуется вывод в определенном формате...
Murr как обычно простелил себе колено
-----
Ну если понимае маленького момента что локаль базы и локаль сессии - это две независимых локали есть выстрел в колено - то - да, прострелил оба...
Как насчет изучения мат.части?
Без документации на формат...или будем дрючить источник?
В этом случае нужно как то добыть информацию, да и задача несколько другая.
В моём случае задача - приложение не должно вылетать при любых ошибках в источнике.
Поэтому что и как выдает источник меня не волнует. Меня волнует, как я буду принимать данные с ошибками.
В моём случае задача - приложение не должно вылетать при любых ошибках в источнике.Поэтому что и как выдает источник меня не волнует. Меня волнует, как я буду принимать данные с ошибками.
О! И если данные приходqт как текст, а ты конвертируешь его в обьект, то должен предусмотреть стандартные возможности - строка пустая или несуществует, строка не может быть конвертирована. И написать юниттесты для этих случаев, как реагирует твой код.
Черный ящик без документации... не тестировать, а мокать... Как?
Элементарно. Какое то представление о черном ящике все таки есть. Ну все публичные методы там присутствуют. С описанием параметров вызова и checked исключениями.
Именно это и мокаем. Мок должен уметь принимать те параметры, какие есть у реального обьекта и возвращать то, что возвращает реальный обьекt
Именно этого мы как раз и не знаем...
Ну во первых мы точно знаем тип данных того, что возвращает обьект. Точно.
Во вторых мы знаем, что делать с тем, что возвращает обьект. Точно.
Поэтому тесты это реакция, как правильно реагирует НАША система на все мыслемые комбинации того, что возвращает чужой обьект. И мок это будет то, как мы себе это представляем.
Например чужой обект возвращает стринг. Значит наш мок должен уметь возвращать и null. И пофиг, может это делать настоящий обьект или нет
Напримет чужой обект возвращает обьект класса. Значит наш мок должен уметь возвращать и
налль и недоинициализированный обьект класса. И пофиг, может это делать настоящий обьект или нет
обект возвращает стринг
-----
Как это замечательно, когда есть стринг! Буковки, циферьки, длина - так много информации с которой можно работать...
А как насчет какого-то двойчного набора слегка перемежаемого прерываниями?
Да и со строками Я как-то обрисовывал весьма проблемный вариант - ЗигБии называется...
А как насчет какого-то двойчного набора слегка перемежаемого прерываниями? Да и со строками Я как-то обрисовывал весьма проблемный вариант - ЗигБии называется...
В меру своей фантазии. Черный ящик возвращает что то. Ты точно знаешь, что с этим делать. Иначе ты вообще не можешь его использовать. Ты ТОЧНО знаешь, какие проблемы могут возникнуть, иначе ты не подготовил СВОЙ код и что же ты собираешься тестовать? Вот мок и возвращяет то, что ты ожидаешь. Все мыслимые варианты. Немыслемые и неожиданные не нужны, ты все равно не готов в своем коде их отрабатывать.
Буковки, циферьки, длина - так много информации с которой можно работать...
Именно. Если твой код имеет 100500 вариантов реакции на различные варианты - нужно 100500 вариантов поведения мока. Да,
тесты рисовать может быть затратно по времени.
Ты ТОЧНО знаешь, какие проблемы могут возникнуть
-----
Ошибаешься.
Самая простая ситуаций - в доках написано - получешь текстовое сообщение из двух частей - длинны текста и самого текста в виде одной строки, где длинна указана в начале и отделена пробелом от остального текста.
Какие проблемы могут возникнуть?
иначе ты не подготовил СВОЙ код и что же ты собираешься тестовать?
-----
А почему Я должен его подготовить? У меня новомодное ТДД - сначал надо написать все тесты, а потом подгоняем под них код...
Вот мок и возвращяет то, что ты ожидаешь.
-----
Так Я не знаю что ожидать.
И доки не помогают т.к. не описывают ситуацию с достаточной полнотой.
Получить хоть какое-то понимание того что будет получатся, когда будет получатся, когда не будет получатся можно только серьезно протестив то с чем надо работать. И то не все сразу отловишь...
имеет 100500 вариантов реакции
-----
Мне, в большинстве случаев, хватает двух - принято и отвергнуто.
А вот какое из них будет - фиг его знает - даже написав корректный код по заданию получается что что-то работает не так как надо...
в доках написано - получешь текстовое сообщение из двух частей
Ну если хоть что то написано, то это меняет дело. Тут уже чистая комбинаторика
Текст/ не текст/ничего
Одна часть/2/больше
А то что документации недостаточно, это никак не меняет дело с одним набором данных.
Можно его тестировать и изучать сколько угодно, но нет никакой гарантии что другой набор даст где то такие же результаты.
Должны быть некие соглашения и определенные рамки изменения данных.
это никак не меняет дело с одним набором данных.
-----
Хи-хи...
В той сети которую Я упомянул до набора данных еще надо дойти.
Причем иногда - в прямом смысле слова - ногами - физически притопать туда где носимое устройство сможет дотянутся до другого, возможно так же носимого - сплошного покрытия сетью там нет - и поиметь возможность что-то получить/отправить.
Тут уже чистая комбинаторика
-----
Угу... Я сначала тоже так подумал... оказалось - зря.
Среди упомянутых нет как минимум еще двух-трех опций...
Причем таких, что даже зная что они возможны будет проблемно получить их с устроства.
На тестирование кода они мало влияют - ну не нашел и не протестил... но гробят обработку на раз... пустяки - подумаешь кто-то загнется от сердечного приступа об котором изначально было сообщение...
Должны быть некие соглашения и определенные рамки изменения данных.
------
Хи-хи... Ты хочешь другой протокол поверх или в дополнение к имеющемуся.
Увы - для этого надо поменять устройство... а после смены оно подлежит повторной сертификации... а на это никто не пойдет.
В той сети которую Я упомянул до набора данных еще надо дойти.
Доступность набора данных - это вообще совершенно другая проблема.
Причем таких, что даже зная что они возможны будет проблемно получить их с устройства.
А зачем их тогда вообще получать, если о них знать?
но гробят обработку на раз
Ну так дело в обработчике. Если правильно написано, то вне зависимости от исходных данных ничего не должно упасть.
Ты хочешь другой протокол поверх или в дополнение к имеющемуся.
Нет, только лишь нормальное описание имеющегося.
А почему Я должен его подготовить?
Потому что неважно с чего ты начинаешь, с тестов или с кода. Ты должен знать, что нужно сделать. Если не знаешь - то ничего делать не надо.
получешь текстовое сообщение из двух частей - длинны текста и самого текста в виде одной строки, где длинна указана в начале и отделена пробелом от остального текста.Какие проблемы могут возникнуть?
Ну получил ты стринг. Ок. Это просто строка. Твой следующий шаг? Что ты будешь со строкой делать?
Так Я не знаю что ожидать.
Тогда ничего не делай. Что ты собираешься программировать, если ты ВООБЩЕ ничего не знаешь? Если ты вообще не знаешь, что придет с черного ящика, ты физически не можешь с ним работать.
т.к. не описывают ситуацию с достаточной полнотой.
Ты можешь запрограммировать (речь идет о исполнении задания) только на ту глубину, насколько ты знаешь "черный ящик". Именно эту глубину ты можешь покрыть тестами, неважно до имплементации задания или посл. Неважно с моком или с реальным обьектом.
Получить хоть какое-то понимание того что будет получатся, когда будет получатся, когда не будет получатся можно только серьезно протестив то с чем надо работать.
Мок - это имитация реального обьекта насколько ты его понимаешь. Слово "серьезно" это несерьезно. Например у тебя неполное понимание работы обьекта и ты слепил мок. Ок. мок несовершенен. Ты "серьезно" гонял настоящий обьект, что бы понять. Ты можешь гарантировать, что понимание теперь 100%? Если нет, то твой мок лучше предыдущего, но принципиально то же самое - то, что он будет копией реального обьекта ты гарантировать не можешь.
Но это и не надо. Еще раз. Ты не учишисья работать с реальным обьектом - "черным ящиком" используя мок. Ты тестируешь СВОЙ код на все известные тебе варианты поведения реального "черного ящика".
Мне, в большинстве случаев, хватает двух - принято и отвергнуто.
Это варианты поведения твоего кода. Вариантов поведения мока больше. Например твой пример для составной строки. Мок прислал пустую строку - отвергнуто-тест прошел. Мок не ответил в таймаут. Мок прислал сообщение о ошибке. Мок прислал строку, где длина в буквах. Мок прислал строку без разделителя. Везде твой код должен отреагировать правильно, пусть одним вариантом реакции, но на 100500 вариантов ответа мока.
А зачем их тогда вообще получать, если о них знать?
------
Их в документации нет, но они иногда случаютя...
и докопаться до них можно только при очень дотошном исследовании...
Если правильно написано, то вне зависимости от исходных данных ничего не должно упасть.
-----
Да ну? Там сеть без квитирования и без гарантии доставки...
только лишь нормальное описание имеющегося
------
Нормальное - есть. Но оно не покрывает фактическую работу устройства.
Мало того - при тестировании единичного устройства многое просто не видно.
Если не знаешь - то ничего делать не надо.
-----
Осталось выяснить как ничего не делая получить работающий код...
Твой следующий шаг?
-----
По документации - вырежу данные и буду с ними работать.
По факту - будет существенно сложнее. Причем настолько, что сразу не понять ни какие проблемы, ни откуда они, ни как с ними разбираться.
Выяснить что-то можно только поработав плотненько с сетью устройств.
Что ты будешь со строкой делать?
-----
Вот это Я у тебя хотел узнать.
ты физически не можешь с ним работать
------
А код надо сдавать и он должен быть рабочим.
только на ту глубину, насколько ты знаешь "черный ящик"
------
Т.е. ровно на столько, сколько написано в документации.
Написанное по документации в практической среде работать не будет.
Ты можешь гарантировать, что понимание теперь 100%?
-----
Нет. Но Я могу поднять понимание с 20% соответствующих документации до 97% соответствующих реальной системе.
Оставшиеся 3% Я все одно не смогу получить от устройства/среды, но могу хоть как-то интерполировать полученные из опыта 77% и задавить еще 2.9%.
Это уже будет неплохой результат. Очень даже хороший по сравнению с исходным. И даже где-то приемлемый.
Где-то, но не везде.
По секрету скажу - уже где-то с 50-60% эффективное решение будет не на уровне кода, а на уровне инфраструктуры - об этом ты вообще пока не задумывался... и даже после прочтения документации эти идеи не появятся.
твой код должен отреагировать правильно
-----
Угу. Осталось выяснить сааамую простую вещь - правильно в соответствии с документацией т.е. в 20% случаев, или правильно в соответствии с реальной ситуацией т.е. 97%.
Для 97% ты пока еще не перечислил все варианты и наиболее проблемную часть пока еще даже не упоминал.
Ты можешь запрограммировать (речь идет о исполнении задания) только на ту глубину, насколько ты знаешь "черный ящик".
Нет и не может быть никакого глубинного знания "черного ящика". У "черного ящика" есть только вход и выход. Как из входа получается выход - магия.
Меня удивляет, что об этом приходится говорить.
Их в документации нет, но они иногда случаютcя
Тогда получается, что мы о них не знаем.
Там сеть без квитирования и без гарантии доставки
У меня складывается впечатление что мы обсуждаем разные вещи.
Ты - свою бывшую проблему.
Я - просто данные
Сеть - это уже способ доставки данных.
Ну и способ доставки данных никак не связан с самими данными.
Это будет интересно только при приеме конкретного пакета.
Было бы интересно "увидеть" пример правильно спроектированного класса для приема данных, который падает при неправильных данных
Нормальное - есть. Но оно не покрывает фактическую работу устройства.
Тогда это неполное описание. Другими словами ненормальное.
при тестировании единичного устройства многое просто не видно
Ну именно это я имел в виду, говоря про единичный набор данных.
И работа устройства это совсем не то, что мы рассматриваем - прием каких либо данных.
Тогда получается, что мы о них не знаем.
-----
Ну так Я об этом уже не первый день говорю.
Да, можно написать в соответствии с документацией. И оно даже будет работать.
Но только в каких-то идеальных условиях.
В реальной среде - работать не будет - получаемое отличается от описанного.
способ доставки данных никак не связан с самими данными.
-----
Способ - нет. А вот что будет получено - уже, увы, да...
неполное описание
-----
Для отдельного изолированного устройства - вполне достаточное.
А так - да, не полное, не описывает многое из того что имеет место быть.
Сеть - это уже способ доставки данных
-----
В данном случае - весьма сильно отличающаяся от привычных tcp/ip сетей.
У меня складывается впечатление что мы обсуждаем разные
вещи.
-----
Угу...
Я всего лишь говорю, что чтобы сделать работающий код надо знать с чем работаешь.
Ну а мне пытаются объяснить что достаточно сделать по документации.
В большинстве случаев написанное по документации - достаточно, но вот в этом случае - нет - надо ковырять реальную сеть чтобы понять возникающие проблемы. Мало того, в данной сети есть проблемы, для понимания которых недостаточно уметь грамотно работать с тцп/ип сетями, хотя, обычно, прикладная программа работает именно с ип&портом... ну или с усб-портом...
У "черного ящика" есть только вход и выход.
-----
Угу...
Вот только не вполне определено что именно понимается под "черным ящиком".
Документация, которая доступна, описывает функционирование отдельного устройства.
Соответственно код написанный по данной документации будет корректно работать с устройством.
Можно тестировать - все пройдет нормально.
Вот только де-факто "черным ящиком" является не устройство, а сеть.
Документации на сеть - нет. Все что есть - устройств может быть много, они могут быть разаными и взаимодействовать.
А поведение устройства в сети весьма отличается от того что описано в документации.
В реальной среде - работать не будет - получаемое отличается от описанного.
Ну так это задача никак не совместима с юнит тестами. В лучшем случае это integration test. И то это чисто для проверки, что мы не сломали то, о чём знаем.
Вот написал я юнит тест для использования функции перемещения файлов. Никакого доступа к диску, никах файлов. Отлично обрабатывает все исключения и прочее.
Но, в реальной среде не работает...иногда. Например, если в каталоге (target) уже есть такой файл, он не перезаписывается, а выдается исключение. Которое обрабатывается правильно.
Почти полная аналогия с твоими устройствами.
Я всего лишь говорю, что чтобы сделать работающий код надо знать с чем работаешь.
А что кто то пытается с этим спорить?
Вот только не вполне определено что именно понимается под "черным ящиком".
Вполне себе определено:
Чёрный я́щик — термин, используемый для обозначения системы, внутреннее устройство и механизм работы которой очень сложны, неизвестны или неважны в рамках данной задачи.
Вот только де-факто "черным ящиком" является не устройство, а сеть.
Ты уж определись, что у тебя там является черным ящиком.
Документации на сеть - нет. Все что есть - устройств может быть много, они могут быть разаными и взаимодействовать.
А поведение устройства в сети весьма отличается от того что описано в документации.
Все это очень мило, но не имеет никакого отношения к юнит-тестам. Да и вообще к тестам. Любой тест, хоть юнит, хоть интергационный, хоть системный, любой, построен на том, что у тебя есть заранее известный вход и заранее известный выход. И есть некий заранее известный сценарий по которому ты гарантированно получаешь конкретную ошибку. Если нет этих 3-х составляющих (вход, выход и сценарий), то ты не можешь убедиться в том, что ошибка была исправлена.
Как видишь, в тестировании нет никаких случайных величин.
Есть правда тестеры, которые ищут ошибки... но в конечном счете из 3-х параметров им известен 1, а остальные 2 (выход и сценарий) они ищут "в слепую". Но рещультат их работы все равно 3 известных параметра - вход, вызод и сценарий. Ну
и лично я считаю, что эта работа - бесполезная трата времени, т.к. стоит дорого, а выхлоп минимальный.
задача никак не совместима с юнит тестами.
-----
Вполне совместима.
Только надо выяснить как именно мокать систему...
Например, если в каталоге
-----
Ну а об чем Я спрашивал когда увидел описание задачи?
В винде там еще и локи на файлах случаются. Причем - неожиданные...
Почти полная аналогия с твоими устройствами.
-----
Аналогия только в том, что глюки редкие. По ФС всегда можно что-то откопать, а по этой сети практически ничего не находится - редкие задачи...
А что кто то пытается с этим спорить?
-----
Ну убедить то меня пытаются в другом...
Осталось выяснить как ничего не делая получить работающий код...
Ты не получишь работающий код. Потому что ты просто не знаешь что делать
-Приезжайте в гости
-А адрес?
-Да не надо адрес, так приезжайте.
Но Я могу поднять понимание с 20% соответствующих документации до 97%
уже где-то с 50-60% эффективное решение
Но почему 97%? Ну откуда ты вообще берешь оценку? Откуда беруться цифры при оценке понимания черного ящика? Ты месяц гонял тесты (ру юниттесты, простое исследование). Те готорые смог придумать и организовать. Как ты оцениваешь полноту тестов?
правильно в соответствии с документацией т.е. в 20% случаев,
Нет. 100% правильно в соответствии с твоим пониманием, как твой код обрабатывает работу черного ящика. Соответственно мок 100% имитирует
твое понимание работы черного ящика. Тестируя месяцы и годы можно улучшить понимание работы самого ящика, но принцип написания мока не меняется - в любой момент времени, сразу после прочтения документации или после 20 лет непрерывных тестов мок 100 процентов имитирует ответ черного ящика в строго определенной ситуации. Определенной тобой, как программистом.
Только надо выяснить как именно мокать систему...
Что то я очень в этом сомневаюсь.
Как я понял, у тебя имелась некая система, данные которой зависят от состояния самой системы, а состояния могут меняться от многих факторов.
И тебе бы хотелось написать тесты позволяющие убедится в работоспособности всей системы.
Ну убедить то меня пытаются в другом...
Мне кажется что нет. Только то, что ты хочешь получить от тестов то, что они тебе дать не могут.
есть заранее известный вход
-----
Никак не хочешь понять что нет заранее известного входа... полностью известного, по крайней мере.
А того что известно - недостаточно для написания того что нужно...
эта работа - бесполезная трата времени
-----
Но и ее тоже надо делать...
Как ты оцениваешь
-----
Если Я каким-то образом получу больше информации об функциомнировании устройства/системы чем есть в документации, то процентик - повысится. Или будет наоборот?
Тебя смущают конкретные цифирьки - ну обоснуй их неправильность...
ответ черного ящика в строго определенной ситуации
-----
Проблема в том, что в конкретном случае у тебя скорее не черный, а серый ящик.
Т.е. у тебя на одно внешнее воздействие имеется более чем один ответ.
И при этом ни один из полученных ответов может не соответствовать описанному в документации.
Понять - можно. Но не програмно. Нужно физически цеплять аппаратный порт к железу и смотреть что там происходит. - тогда станет более-менее понятно чего надо ожидать в качестве ответа устроства/системы...
Если Я каким-то образом получу больше информации об функциомнировании устройства/системы чем есть в документации, то процентик - повысится.
Вопрос стоял о целесообразности мероприятия. Например берем устройство и изучаем. И доклад - повысили информированность о системе до 97% - это одно. Доклад - а процентик то повысился Или наоборот? - это другое. Особенно если изучали месяц и к концу изучения забыли, что изучали
ебя смущают конкретные цифирьки - ну обоснуй их неправильность...
Основой для получения циферок является критерии оценки конечного результата. И в первую очередь критерии целесообразности мероприятия. Хочу все знать - это не критерий. Цифры могут быть там, где критерии оценки в цифрах. Я стал умнее информированиее на 30% - это лохотрон по определению. Просто нет критериев для оценки.
Т.е. у тебя на одно внешнее воздействие имеется более чем один ответ.И при этом ни один из полученных ответов может не соответствовать описанному в документации.
Выглядит как божественный процесс создания женщины. У Бога тоже не было документации, надо было сделать обязательно, непонятно что, задумка была прекрасная. Ну и получилось то, что получилось - "на одно внешнее воздействие имеется более чем один ответ.И при этом ни один из полученных ответов может не соответствовать"
Но и ее тоже надо делать...
Если какую-то деятельность можно описать как "бесполезная трата времени", то такую работу делать не надо... Ну если только тебе людей нечем занять и чтобы они не сидели без дела, тогда можно убить их время эмитируя полезную нагрузку :)