Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Unit Test. Кто использует?

1707  1 2 3 4 5 6 все
Программист коренной житель01.11.16 22:48
NEW 01.11.16 22:48 
в ответ moose 01.11.16 22:11
А применим ли юнит тест в мультипоточной среде?

применим


Как можно протестировать "юнит", если результат зависит от того, что происходит в других потоках?

Ответ на вопрос "как можно протестировать" зависит от того, ЧТО ты хочешь протестировать. Если ты знаешь что ты хочешь протестировать, то дальше все сравнительно просто - эмулируешь работу других потоков и тестируешь :)

Понимаю, что это звучит несколько странно, но это возможно сделать. И потом, как я уже говорил, не любой существующий код можно протестировать юнит-тестом. Нужно писать такой код, который может быть протестирован.

Вот например такой код невозможно протестировать юнит-тестом:

public bool ShouldArchive(string fileName)
{
if (File.Exists(fileName) == true)
{
FileInfo fi = new FileInfo(fileName);
return (fi.Length > 1000) ? true : false;
}

throw new ArgumentException("File does not exists");
}

Т.е. протестировать этот код конечно можно, но это будет не юнит-тест :)


#61 
Программист коренной житель01.11.16 22:56
NEW 01.11.16 22:56 
в ответ moose 01.11.16 22:19
Откуда уверенность, что он именно поэтому не дает сбоев?

Ну потому что я вижу, что сбои случаются либо там, где не было тестов, либо там, где мой код допиливали индусы (которые у нас не заморачиваются юнит-тестами).


т.е. юниттесты не везде применимы, а только к тем элементам, которые - позволяют их протестировать независимо (согласитесь, не любой элемент это позволяет)- элементы относительно просты, т.к. если тест выполняется быстро, то и сам элемент тоже- элементы опять же просты, т.к. имеют обозримое (и небольшое) количество юзкэйсов (иначе мы бы заковырялись их писать)

Это все неверные утверждения :) Да, не любой код можно протестировать юнит-тестами, но всегда можно написать тестируемый код. Просто для этого надо подумать :) Ну и желательно сначала написать тест, а потом рабочий код.

Прочитай книжку Роя Ошерова. И ты поменяешь свою точку зрения ;)


#62 
AlexNek патриот01.11.16 23:12
AlexNek
NEW 01.11.16 23:12 
в ответ moose 01.11.16 22:19
что серебрянная пуля юнит тест (и тдд) нэт

ну так это было еще ясно и в самом начале, вроде.

Если говорить о "надежности" ПО то она складывается из большого числа кирпичиков, одним из которых является автоматическое тестирование кода.


Эх, сколько я их уже перевидел, этих модных технологий!

А что сейчас настала мода на юнит тесты? Сорри, не знал, вроде уж больше 10 лет енто живёт.


Хотя использование юниттэстов для определенных элементов должно быть полезно.

Тут я бы использовал следующее:

"Хотя использование юниттэстов для определенных элементов полезно."

#63 
  Пупкин прохожий07.11.16 13:51
NEW 07.11.16 13:51 
в ответ Программист 01.11.16 17:13, Последний раз изменено 07.11.16 14:02 (Пупкин)
Если Вася Пупкин диверсант

Господин "Програмист", у вас совесть есть ? Причем здесь я и диверсанты какие-то ?


#64 
MrSanders старожил08.11.16 08:50
NEW 08.11.16 08:50 
в ответ Программист 01.11.16 22:48
Т.е. протестировать этот код конечно можно, но это будет не юнит-тест :)

Почему нет? Раз есть доступ к файловой системе вы сразу будете считать тест интеграционным?

Можно же перед вызовом метода создать временный файл в системном темпе, а после теста стереть.

#65 
Программист коренной житель08.11.16 09:30
NEW 08.11.16 09:30 
в ответ MrSanders 08.11.16 08:50
Раз есть доступ к файловой системе вы сразу будете считать тест интеграционным?

Не только к файловой системе, а вообще к любому внешнему элементу.


Можно же перед вызовом метода создать временный файл в системном темпе, а после теста стереть.

можно конечно, но юнит-тест должен быть быстрым... в моем примере проверка идет на 1000 байт и такой файл можно быстро создать. а если это не 1000 байт, а скажем, 400Мб? успеешь на пенсию выйти пока файл этот создашь :) я уж не говорю о том, что проблема может быть в случае, если файл где-нибудь в сети, а на локальной машине все работает. будешь в тесте не только файл создавать, но и подключение к сети? :)


а если тест будет исполняться много времени, то в лучшем случае тест этот будет выполняться раз в сутки. а в худшем случае тест этот вообще выключат из плей-листа, т.к. работать он будет от раза к разу (например из-за нехватки места на диске)


так что таким тестом крайне сложно, а зачастую просто невозможно, покрыть (смоделировать) действительно проблемные ситуации.

например, такой подход не даст тебе возможность протестировать сценарий, при котором будет сгенерировано исключение. а юнит-тестом такой сценарий легко покрывается.

#66 
MrSanders старожил08.11.16 11:30
NEW 08.11.16 11:30 
в ответ Программист 08.11.16 09:30
так что таким тестом крайне сложно, а зачастую просто невозможно, покрыть (смоделировать) действительно проблемные ситуации.

Ок, согласен.

#67 
Simple Nothing is f*cked08.11.16 17:54
Simple
NEW 08.11.16 17:54 
в ответ Программист 01.11.16 22:48

А если заглушку прикрутить? :)

Проникся твоим энтузиазмом, нашел книгу Ошеров, буду внедрять по полной :)

#68 
Программист коренной житель08.11.16 19:28
NEW 08.11.16 19:28 
в ответ Simple 08.11.16 17:54

Так вот чтобы прикрутить заглушку надо зачастую очень многое менять в коде.

Во-первых, код надо делать на интерфейсах и виртуальных функциях.

Во-вторых, нельзя использовать статические функции.

В-третьих, создавать новые объекты через фабрики, т.е. никаких new MyCoolClass () в коде.

В-четвертых, надо делать обертки над системными функциям, т.е. никаки File.Exists(fileName).


Казалось бы, что все это очень простые правила, но следовать им не так просто, особенно, если код уже существует.

Но следовать этим правилам помогает TDD.


Проникся твоим энтузиазмом, нашел книгу Ошеров, буду внедрять по полной :)

Удачи! Я до этой книжки тоже был довольно скептично настроен на счет юнит-тестов и TDD, но проникся :) Стал использовать в своих проектах и эти методики реально работают. Попробуй и ты возненавидишь статические функции и new в коде :D :D :D


Помню у нас было проблемное место связано с подсчетом свободного места на диске. Буквально каждую неделю приходили новые баги. При этом пофиксишь один и всплывает либо новый, либо ломается то, что пофиксил недели 2-3 тому назад. Я тогда переработал код, сделал обертку надо System.IO.Directory и сделал юнит тесты. Багов в том месте больше нет :) И там были именно такие проблемы, что диск вроде виден, но нет прав на запись. Или путь к папке есть и все ОК, но места недостаточно. Или все есть, но слишком длинный путь. И куча всего другого. Все эти проблемы легко закрываются юнит-тестами и совершенно невозможно протестировать на уровне QA или интеграционными тестами. Более того, у нас потом ввели анализатор статического кода и индусы пофиксили многие "баги", так все это всплыло еще до того, как они закомитили код :) Все вернули и добавили SuppressMessage с соответствующими комментариями. И никаких проблем :)

#69 
Simple Nothing is f*cked08.11.16 19:35
Simple
NEW 08.11.16 19:35 
в ответ Программист 08.11.16 19:28

Да, я в курсе в общем и целом. Также понимаю, что существующие проекты невозможно покрыть тестами даже чуть-чуть, но пытаться надо, иначе можно сразу вскинуть лапки :)

Попробуй и ты возненавидишь статические функции и new в коде :D :D :D

Да уже :) А также многое другое.

#70 
Simple Nothing is f*cked08.11.16 19:36
Simple
NEW 08.11.16 19:36 
в ответ Программист 08.11.16 19:28

пс Заглушку можно приделать, даже ничего не меняя в коде.

#71 
Программист коренной житель08.11.16 20:21
NEW 08.11.16 20:21 
в ответ Simple 08.11.16 19:36

Зависит от того, что заглушать и где. Статическую функцию или созданный в коде объект заглушкой, без изменений, не закроешь.


Нет, есть конечно фреймворки, которые способны заглушать статические функции (Ошеров о них пишет), но там тоже есть обратная сторона.


Но это все детали. Мне в TDD понравилось то, что ты должен сначала задуматься о том, чего ты хочешь достичь.

Мы как-то с коллегой экспериментировали с 4 eyes principle и TDD. Получилось очень интересно. Во-первых, оказалось, что тестировать надо гораздо меньше, чем коллега изначально хотел тестировать. Во-вторых, тесты оказались гораздо проще, чем он предполагал. И в-третьих, тестировали совсем не то, что он изначально хотел тестировать :)

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

Ну а споры о том, надо ли тестировать WPF у нас возникают с интервалами в 2-3 недели :)

#72 
Simple Nothing is f*cked08.11.16 20:58
Simple
08.11.16 20:58 
в ответ Программист 08.11.16 20:21

В смысле, тестировать сам впф или код на нем? :)

#73 
Программист коренной житель08.11.16 21:11
NEW 08.11.16 21:11 
в ответ Simple 08.11.16 20:58

Ну биндят свойство, скажем, Enabled с проперти IsValid. Типа, если IsValid == true, то кнопка активная, а если нет, то нет.

И потом порываются написать UI тест, который бы проверил, активная кнопка или нет.


Я говорю, нафига этот тест нужен? Проверь работу проперти IsValid, все остальное делает WPF и делает он это правильно. И тест проще и прогонится быстро.


Но люди у нас упорные :) Любят создавать себе проблемы и ненужные задачи :D

#74 
Murr_0001 знакомое лицо09.11.16 14:27
Murr_0001
NEW 09.11.16 14:27 
в ответ Программист 08.11.16 21:11

N.P.


К вопросу об тестировании...


Сижу третий день над тестом.


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

Список получается из базы одним из четырех запросов.

Важно - струтура возвращаемых данных - своя у каждого из четырех запросов.


Требуется - предоставить один из 5 возможных результатов:

- отдельный номер,

- список номеров,

- список номеров с детализацией количества,

- одна из двух констант - не надено или просрочено.


Вроде все не сложно... но уже голову сломал - то не тот метод, то не та структура...


Как такую дрянь тестить?

#75 
Программист коренной житель09.11.16 15:51
NEW 09.11.16 15:51 
в ответ Murr_0001 09.11.16 14:27, Последний раз изменено 09.11.16 15:52 (Программист)
Как такую дрянь тестить?

Первое, что надо сделать - забыть о существовании базы данных :)


Далее было бы не плохо понимать:

1) каким образом выбираются запросы? в каком виде они используются (это просто выбор строки через if/switch или каждый запрос - это унаследованный от IMurrQuery класс или что-то еще)?

2) каким образом формируются запросы?

3) как выглядят возвращаемые данные (опять же отдельный класс унаследованный от IMurrData на каждый тип данных или один общий Dictionary)?

4) каким образом формируются возвращаемые данные?


Ну а дальше заглушки на все. Потом тестируешь по отдельности каждый юнит:

1) генерация правильного запроса (количество тестов зависит от сложности количества критериев выбора)

2) формирование одного из 5 возможных результатов на базе каждого из возможных ответов от запроса.


Если я правильно понял, то процесс примерно такой:


Т.е. у тебя 2 независимых друг от друга модуля, которые надо протестировать.


#76 
Murr_0001 знакомое лицо09.11.16 20:21
Murr_0001
NEW 09.11.16 20:21 
в ответ Программист 09.11.16 15:51

Далее было бы не плохо понимать:

-----

1. Код объемом примерно 1600 строк содержит логику выбора запроса.

2. В оригинальной версии - существует дополнительный блок функций, отвечающий за построение запросов. Там не много - 1000 строк. В моей версии - функции заменены Т4-шаблонами, генерирующими скл-техт (мне так проще).

3. ДатаТабле. В моей версии - есть общие ААбстрактКласс и ИИнтерфейс. Производная - строго типизированное представление, но оно ОДНО вместо ТРЕХ.(Понимаю что неправильно, но доделывать могу после того как задышит).

4. Не понятно. Запрос к базе возвращает таблицу ДатаТабле. На базе таблицы строится одна из трех строк - отдельный номер, список или список с детализацией.


2) формирование одного из 5 возможных

-----

Анализ - почти правильный. Только вот не выходит...

Т.е. 3 метода генерации списка Я разумеется написал, а вот получить правильный ответ от системы - не выходит...

Ну если за завтра не добью, то в тяпницу меня разбанят на "рабочем" аккаунте и запощу исходнички... повеселимся после обеда...

#77 
Программист коренной житель10.11.16 08:52
NEW 10.11.16 08:52 
в ответ Murr_0001 09.11.16 20:21

:) не я же буду это все тестировать :) понимать, и быть готовым менять, должен ты :) скорее всего существующий код плохо поддается тестированию и если хочешь тестировать этот код юнит-тестами, то придется этот код менять.

основные перемены связаны с тем, чтобы можно было подменить любой вызов.

Например код типа такого (MyDateTime - обертка над System.DateTime):

public IQuery GetQuery (ISettings settings, IParameters parameters)
{
      EQueryType queryType = GetQueryType (settings);

      if (MyDateTime.Now.Day % 2 == 0 &&  (int)queryType % 2 == 1)
      {
           throw new MyException ("This exception can NEVER be thrown!");
      }
      else if (MyDateTime.Now.Day % 2 == 0)
      {
           queryType++;
      }

      IQuery query = GenerateQuery (queryType, parameters)
      if (query == null)
           throw new MyException ("Something went wrong!")

      return query;
}

protected virtual EQueryType GetQueryType (ISettings settings)
{
    ....
}

protected virtual IQuery GenerateQuery(EQueryType queryType, IParameters parameters)
{
    ....
}


тестируется очень легко. Собственно говоря, для этого кода достаточно 4 тестов:

1) спровоцировать исключение "This exception can NEVER be thrown!"

2) убедиться, что queryType увеличилось на 1

3) спровоцировать исключение "Something went wrong!"

4) убедиться, что функция завершается без исключений


Ну а функции GetQueryType и GenerateQuery тестируются отдельно.


вот получить правильный ответ от системы - не выходит...

не выходит правильно преобразовать raw данные в нужный тебе вид?

#78 
  moose местный житель10.11.16 10:28
NEW 10.11.16 10:28 
в ответ Программист 08.11.16 21:11, Последний раз изменено 10.11.16 10:59 (moose)

Вы написали, например, ... Enabled={DynamicResource IsValid}, а кто-то где-то прочитал, что динамический байндинг - туфта, и заменил DynamicResource на StaticResource во всем файле (проекте). И Ваша клавиша стала навеки такой, какой была при создании. Или кто-то решил "в критическом месте" просто "обезопасить" клавишу и написал button.Enabled = false; или наоборот, "надежно обеспечить доступность клавиши": button.Enabled = true; а теста у Вас нет. Конечно, это неопасно, т.к. при первом же визуальном тесте на это напорются. Но Вы говорите - не надо тестировать, там ничего не может пойти криво.

#79 
  moose местный житель10.11.16 11:05
NEW 10.11.16 11:05 
в ответ Murr_0001 09.11.16 14:27

Если я правильно понял "учебник", то описываем интерфейс вроде IGetInvoiceList, имплементируем один рилизный, который полезет в базу, и один тестовый, который будет возвращать тестовый список из пяти Ваших вариантов. Далее можете требуемый инстанц или прямо в запросе передать, или в конструкторе, или как проперти, что больше нравится или подходит.

#80 
1 2 3 4 5 6 все