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

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

1707  1 2 3 4 5 6 все
Программист коренной житель01.11.16 08:48
NEW 01.11.16 08:48 
в ответ AlexNek 31.10.16 23:02

Нет, никаких особенных требований нет :) C# разработчик со знанием C++ (давно не писал на плюсах). Из особенных know-how - MSI, WiX. Сейчас вот освоил юнит-тесты и TDD :)


pavel-hh, спасибо за предложение, но Java это не мое :)


#41 
Программист коренной житель01.11.16 09:03
NEW 01.11.16 09:03 
в ответ moose 31.10.16 23:08
А применим ли юнит тест в мультипоточной среде?

Конечно. Вообще не важно, в какой среде :)


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

Юнит-тест должен быть независим от "внешних" факторов. Поэтому совершенно не важно сколько там потоков. Ты тестируешь логику только одного потока (aka одной функции). Все, что происходит вне этого потока должно быть закрыто заглушками. Тут есть другая крайность - могут быть ситуации, когда создание заглушек слишком трудозатратнвый процесс или если заглушка содержит ошибку (такое тоже бывает :D)


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

#42 
MrSanders старожил01.11.16 12:05
01.11.16 12:05 
в ответ Программист 01.11.16 09:03
А применим ли юнит тест в мультипоточной среде?

Конечно. Вообще не важно, в какой среде :)

Мне кажется вы ответили правильно но не на тот вопрос :) Юнит-тесты независимы от внешних факторов (и очередности исполнения), да. Но что делать если в тестируемом классе / методе запускаются н-цать потоков и пытаются одновременно что-то сделать (да хоть события из очереди обработать). Внешних факторов нет.

Я понял вопрос moose-а как "а можно ли юнит-тестами найти ошибки, вызванные использованием нескольких потоков", верно, тов. moose?

#43 
Программист коренной житель01.11.16 13:05
NEW 01.11.16 13:05 
в ответ MrSanders 01.11.16 12:05
Но что делать если в тестируемом классе / методе запускаются н-цать потоков и пытаются одновременно что-то сделать (да хоть события из очереди обработать). Внешних факторов нет.

А мне кажется, что я правильно ответил именно на тот вопрос :)


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

Что в приведенной задаче является unit under test? Запуск ли это н-цати потоков? Выборка событий из очереди? Обработка события в потоке? Работа в режиме, когда потоки вынуждены ждать новых событий? Или это работа в режиме, когда потоки не справляются с поступающими событиями? В общем случае есть как минимум 3 unit under test: менеджер потоков, логика самого потока и очередь. В наиболее простом случае, тестировать нужно только логику самого потока, потому что создание потоков тестируется совершенно элементарно (достаточно одного теста, да и тот наверное не обязателен), а ConcurrentQueue<T> тестировать не надо, там уже все протестировано за нас.


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

#44 
AlexNek патриот01.11.16 13:20
AlexNek
NEW 01.11.16 13:20 
в ответ Программист 01.11.16 08:48

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

#45 
MrSanders старожил01.11.16 14:00
NEW 01.11.16 14:00 
в ответ Программист 01.11.16 13:05

Можно не усложнять. Есть метод, который надо протестировать. Black box. Ориентируемся на спецификации - на входе А, на выходе Б.

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

#46 
Murr_0001 знакомое лицо01.11.16 14:33
Murr_0001
NEW 01.11.16 14:33 
в ответ MrSanders 01.11.16 14:00

Мой ответ - нет, нельзя.

-----

И чем это отличается от ответа Программиста?

#47 
Программист коренной житель01.11.16 14:35
NEW 01.11.16 14:35 
в ответ MrSanders 01.11.16 14:00

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


но давай поставим вопрос иначе:

есть задача написать какой-то black box, внутри которого куча потоков итд... можно ли написать этот black box так, чтобы гарантировать работоспособность каждого элемента этого black box'а при помощи юнит-тестов? Мой ответ - можно.


Ну а если тебе дается back box в виде 3rd party библиотеки, то ты должен исходить из того, что библиотека эта работает корректно. Во-первых, ты все равно не сможешь проверить все возможные варианты использования этой библиотеки, а во-вторых, даже если ты найдешь какую-то ошибку, ты все равно не сможешь ее исправить. Отвечай за свой код, а не за чужой. И, как я уже говорил, исходи из того, что чужой код не содержит ошибок.

#48 
MrSanders старожил01.11.16 16:13
NEW 01.11.16 16:13 
в ответ Программист 01.11.16 14:35
можно ли написать этот black box так, чтобы гарантировать работоспособность каждого элемента этого black box'а при помощи юнит-тестов? Мой ответ - можно.

Однозначный jein :)

Написать так что тест будет гарантировать работоспособность можно. (но как проверить что написал именно так?) Но этот тест не вскроет ошибки, внесенные пре рефакторинге.

Допустим мы переписали код так, что любой доступ к данным из разных потоков синхронизирован. Ошибок, связанных с параллельным доступом в таком коде не будет, юнит-тест будет находить логические ошибки в коде, все отлично. Через месяц Вася Пупкин делает рефакторинг и добавляет доступ к новому полю данных - не синхронизированный. Обнаружит ли юнит-тест ошибку, связанную с внеочередным доступом к данным? А как повезет.

Чтобы от такого спасаться надо еще и статический анализ кода подключать, да правила ему давать вроде "в классах с аннотацией @ThreadSafe все get/set методы синхронизированы" (конечно, Вася и такое обойти сможет).

#49 
Программист коренной житель01.11.16 17:13
NEW 01.11.16 17:13 
в ответ MrSanders 01.11.16 16:13
Через месяц Вася Пупкин делает рефакторинг и добавляет доступ к новому полю данных - не синхронизированный. Обнаружит ли юнит-тест ошибку, связанную с внеочередным доступом к данным? А как повезет.

Вообще-то это скорее вопрос дизайна :)


Если Вася Пупкин диверсант, то фирму ничто не спасет и код в любом случае будет нерабочим.

#50 
MrSanders старожил01.11.16 17:29
NEW 01.11.16 17:29 
в ответ Программист 01.11.16 17:13
Вообще-то это скорее вопрос дизайна :)

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

Если Вася Пупкин диверсант, то фирму ничто не спасет и код в любом случае будет нерабочим.

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

#51 
  moose местный житель01.11.16 17:32
NEW 01.11.16 17:32 
в ответ MrSanders 01.11.16 12:05, Последний раз изменено 01.11.16 17:33 (moose)

Нет, попробую сформулировать иначе.

Всегда ли применим юнит тест при наличии многопоточности?


Например, у нас имеется некий метод

Msg* get_next (){

Msg *pMsg = null;

...

return pMsg;

}


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

#52 
MrSanders старожил01.11.16 17:59
NEW 01.11.16 17:59 
в ответ moose 01.11.16 17:32, Последний раз изменено 01.11.16 18:01 (MrSanders)

Э нет, а вот тут мы вас поправим. В этом случае юнит-тест применим. Потому как главное, о чем уже тов. Программист писал, юнит тест независим от окружения.

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


P.S. Причем перед вызовом тестируемого метода я бы еще и проверил, что очередь, из которой сообщение брать будут, пуста.

#53 
  moose местный житель01.11.16 18:12
NEW 01.11.16 18:12 
в ответ MrSanders 01.11.16 17:59, Последний раз изменено 01.11.16 18:13 (moose)

И что мы таким образом проверим? Допустим, у нас есть для посылки сообщения процедура

bool sendMsg (Msg *pMsg){

...

}

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

#54 
Программист коренной житель01.11.16 18:21
NEW 01.11.16 18:21 
в ответ MrSanders 01.11.16 17:29
Ну да, доступ ко всему - через синхронизированную очередь.

Я бы сказал, что через единый интерфейс.


Не только лишь все понимают что проще купить сервер помощнее чем экономить микросекунды на синхронизации и оплачивать недели поиска причин спорадической ошибки.

Все это не имеет никакого отношения к юнит-тестированию.


Иногда потокам надо лезть к одним и тем же объектам. А ошибку в таком доступе юнит тестом (достоверно) не обнаружить.

Ну да, я понял. Лезть надо к одним и тем же объектам и при этом без синхронизации, потому что синхронизация - это дорого :)


Кстати, написание юнит-тестов делает разработку дороже где-то в 1,5-2 раза.


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

Конечно. Наличие юнит-тестов не гарантирует отсутствие ошибок. TDD и юнит-тестирование позволяет обойти многие проблемы за счет того, что написанием юнит-теста разработчик устанавливает требования, а productive code эти требования удовлетворяет.


#55 
  moose местный житель01.11.16 18:22
NEW 01.11.16 18:22 
в ответ Программист 01.11.16 08:48
освоил юнит-тесты и TDD

что из перечисленного ниже гилт:


0 освоил, но пока не применял, но применить хочится, "кушат нэмагу"

1 освоил, пока не применял, и не свербит пока, жду пока случай подвернется

2 применял лишь частично (пояснить)

3 применял, но не уверен, что правильно

4 применял, доволен

5 примерял, разочарован

6 ни одно из перечисленного (привести правильный ответ с пояснением)

#56 
Программист коренной житель01.11.16 19:08
NEW 01.11.16 19:08 
в ответ moose 01.11.16 18:12
И что мы таким образом проверим?

Давай зайдем с другой стороны.

Вот у тебя есть метод:

Msg* get_next (){

Msg *pMsg = null;

...

return pMsg;

}


А что ты хочешь проверить юнит-тестом? :)

Ты можешь расписать по пунктам?

#57 
Программист коренной житель01.11.16 19:16
NEW 01.11.16 19:16 
в ответ moose 01.11.16 18:22

4 - применял и доволен.

Более того, стараюсь применять и дальше. Как показывает моя практика покрытый юнит-тестами код сбоев не дает.


Правда тут есть некоторые оговорки:

1) это должны быть реальные юнит-тесты

- юнит-тесты должны быть независимы (в том числе и от системы)

- юнит-тесты должны быть быстрыми

- один юнит-тест должен покрывать определенный юз-кейс (т.е. один assert на тест)

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

#58 
  moose местный житель01.11.16 22:11
NEW 01.11.16 22:11 
в ответ Программист 01.11.16 19:08
А что ты хочешь проверить юнит-тестом? :)Ты можешь расписать по пунктам?

Так это я спрашиваю, собственно, уместно ли в мультипоточной среде говорить о юнит тестах юнитов, которые бессмысленно рассматривать в отрыве от мультипоточности? Я уже раньше это "по пунктам" сфорумлировал. Повторю:


А применим ли юнит тест в мультипоточной среде? Как можно протестировать "юнит", если результат зависит от того, что происходит в других потоках?
#59 
  moose местный житель01.11.16 22:19
NEW 01.11.16 22:19 
в ответ Программист 01.11.16 19:16, Последний раз изменено 01.11.16 22:32 (moose)
Как показывает моя практика покрытый юнит-тестами код сбоев не дает.

Откуда уверенность, что он именно поэтому не дает сбоев? Это, наверное, говорит скорее с пользу или бесполезности этих юнит тестов, или это как раз потому, что:


1) это должны быть реальные юнит-тесты
- юнит-тесты должны быть независимы (в том числе и от системы)
- юнит-тесты должны быть быстрыми
- один юнит-тест должен покрывать определенный юз-кейс (т.е. один assert на тест)

, т.е. юниттесты не везде применимы, а только к тем элементам, которые

- позволяют их протестировать независимо (согласитесь, не любой элемент это позволяет)

- элементы относительно просты, т.к. если тест выполняется быстро, то и сам элемент тоже

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


Т.е. относительно простые части Вашего кода, которые дают себя проюниттестировать, не дают сбоев как раз в силу своей относительной простоты. А более сложные логически участки, видимо, дают сбои. И не потому, что там не так густо юниттестируется, а потому что сложные вещи (со многими логическими взаиамосвязями и зависимостями) или не поддаются юниттестированию, или оно еще сложнее, чем сам тестируемый код.


Могу сделать из уже имеющегося обсуждения, что серебрянная пуля юнит тест (и тдд) нэт. И применение их довольно ограничено. Это - очередная попытка "уменьшить количество ошибок в программе". Помню времена, когда была мода на try-catch блоки, да и многое другое. Целые языки программирования рассматривались в свое время как "позволяющие программировать без ошибок". Эх, сколько я их уже перевидел, этих модных технологий! Каждая оставляет после себя некий рациональный след, но очень немногие оказываются тем, что ожидают их приверженцы, когда они появляются и входят в моду. Утихнет и этот шум.


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

#60 
1 2 3 4 5 6 все