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

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

1707  1 2 3 4 5 6 все
  moose местный житель27.10.16 15:10
27.10.16 15:10 

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

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

#1 
Программист коренной житель27.10.16 15:48
NEW 27.10.16 15:48 
в ответ moose 27.10.16 15:10

Тут надо разделать автоматическое тестирование и Unit Testing.

По большому счету, Unit Testing не имеет смысле вне TDD. Однако все мы живем в реальном мире, а не в мире эльфов, поэтому во-первых, под юнит-тестами понимают все автоматические тесты, во-вторых, о TDD вспоминают исключительно на ретроспективе :D


Что касается нас, то всякими разными тестами у нас покрыто около 65-70% кода. Цель - 80%. Без тестов была бы полная беспросветная жопа. Поэтому тесты крутятся каждый день и рарезультаты тестирования лежат каждое утро в ящике :) Другое дело, что половина тестов у нас непривильные и поэтому если из примерно 1500 тестов 10-20 не сработали, то всем пофиг :) Но это уже другая тема.


Тестировать надо с умом, а не каждый метод :) Если интересна эта тема, то советую прочитать Roy Osherove - The Art of Unit Testing

#2 
natuerlich blond старожил27.10.16 19:51
natuerlich blond
NEW 27.10.16 19:51 
в ответ moose 27.10.16 15:10

У нас нет конкретного требования по проценту покрытия, поскольку много UI, но считается, что основные функции системы должны быть протестированы. Для меня это все слишком обтекаемо, потому что здесь как раз начинаются спекуляции плана "это можно было бы и не тестировать".

Но я считаю, что юнит-тестинг необходим по ряду причин:

- тестируешь чисто для себя, правильно ли работает твоя функция

- ты независим от того, готовы ли другие части системы или приходят ли данные из других систем

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

- если другие написали тесты, то ты можешь проверить, не сломал ли ты что-то

При этом нужно исходить из того, что тесты имеют смысл и не подогнаны под имплементацию.


Это что касается юнит-тестинга. Но здесь нужно учитывать, что такие тесты как правило делаются на моках, а значит не позволяют тестировать übergreifend, тестирование UI тоже очень ограничено, если вообще возможно. Поэтому необходимо интеграционное тестирование, а также для Last и Performance.

#3 
Murr_0001 знакомое лицо27.10.16 20:13
Murr_0001
NEW 27.10.16 20:13 
в ответ moose 27.10.16 15:10

И сколько единиц у вас в проекте

-----

По сумме - около 2Гб кода. Код, в основном, ВБ-лике - переменные, функции, функции, функции...



какой процент из них охвачен этим делом

-----

Исходный код - 0%, в переработанном коде - 5-6%% - не хватает времени на написание...



сколько времени занимает имплементировать тест (в сравнении с созданием единицы)

-----

от 10 минут до пары дней... бывает - с перерывами на неделю-месяц-полгода...

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

#4 
AlexNek патриот28.10.16 00:11
AlexNek
NEW 28.10.16 00:11 
в ответ moose 27.10.16 15:10

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

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

Как раз был такой случай, тестер так модули вызвал, что мы бы никогда бы не додумались о данной комбинации, ну и конечно, работало не так как требовалось. Пришлось довольно много переписывать.


Сделать покрытие тестами хотя бы больше 50% кода достаточно затратно, а при подъеме покрытия наверх затраты резко возрастают. При этом чем больше тестов, тем больше проблем, особенно когда они "перестают работать".

Часто проблемы "приятные" - видно что нахренячил кто то. А бывает, что после продолжительного анализа так и непонятно отчего тест перестал работать. "Интересно" также искать ошибки, когда последовательность вызова тестов меняется.


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

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

#5 
Simple Nothing is f*cked28.10.16 10:45
Simple
NEW 28.10.16 10:45 
в ответ moose 27.10.16 15:10

У меня все проекты - легаси, никаких тестов там нет от слова "ваще". Что приводит иногда к интересным феноменам в продакшн типа NPE :(

Мечтаю когда-нить поработать в проекте с использованием тдд или типа того.

#6 
  moose местный житель28.10.16 11:38
NEW 28.10.16 11:38 
в ответ Программист 27.10.16 15:48, Последний раз изменено 28.10.16 11:59 (moose)

Спасибо за ссылку. Книгу нашел в пдф, но наверное пойду куплю бумажную. Хорошую книгу нужно читать не с экрана.

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

Я себе плохо представляю, что кто-то полезет там когда-нибудь что-то менять, и если, например, метод конкатенатит две строчки хитроумным образом, в нем никто ничего не менял, и он вдруг стал это делать иначе. Скорее не наш тест, который задает все время одни и те же тестовые строки, а жизнь закинет туда что-то такое, чего мы не ожидали, и нам придется менять ф-ю. Да, здесь пригодились бы наши изначальные тесты, чтобы убедиться, что они после изменений все еще проходят, но если они раз прошли, они будут проходить, сколько их ни крути. Т.е. по определению та же ф-я с теми же данными должна выдавать одинаковый результат. Исключение - неинициализированные переменные, когда случайные начальние значения возможны, и они могут принимать значения, похожие на "настоящие". Или что-то не так понимаю?

Ладно, прочту книгу, наверняка человеческий опыт что-нибудь нового подкинет.

#7 
kitov знакомое лицо28.10.16 11:53
NEW 28.10.16 11:53 
в ответ Simple 28.10.16 10:45

У меня все проекты - легаси, никаких тестов там нет от слова "ваще". Что приводит иногда к интересным феноменам в продакшн типа NPE :(

Мечтаю когда-нить поработать в проекте с использованием тдд или типа того.

Даже с легаси можно применять практики ТДД. На эту тему есть неплохая книга -> https://www.amazon.de/Working-Effectively-Legacy-Robert-Ma...

#8 
Simple Nothing is f*cked28.10.16 12:35
Simple
NEW 28.10.16 12:35 
в ответ kitov 28.10.16 11:53

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

#9 
Программист коренной житель28.10.16 12:56
NEW 28.10.16 12:56 
в ответ moose 28.10.16 11:38
Или что-то не так понимаю?

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


Что касается твоего примера с конкатенатом, то тут слишком простой пример :) Представь себе функцию с cyclomatic complexity 5 или больше :) да еще с вызовами каких-нибудь других функций (самое убийственное, если эти функции статические да еще 3rd party) :). Результат такой функции может легко поменяться после банального апдейся какой-нибудь сторонней системы ;)


#10 
Пирт гость28.10.16 19:10
NEW 28.10.16 19:10 
в ответ moose 28.10.16 11:38, Последний раз изменено 28.10.16 19:13 (Пирт)

У нас все о них говорят, и о TDD. О TDD - что, мол, "мы следуем", но при этом никакого TDD и в помине нет (это тот еще философский вопрос, надо ли).

Покрытие кода у нас 60-70%, полет нормальный =)


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


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

#11 
  moose местный житель28.10.16 23:29
NEW 28.10.16 23:29 
в ответ Пирт 28.10.16 19:10, Последний раз изменено 28.10.16 23:31 (moose)

О "человеке" Вы истину написали. Мой опыт: шеф имеет одного человека, мнению которого доверяет. Этот человек "уснул" где-то году в 2000-м, но на все сразу имеет готовый категоричный ответ ("ВСЕ - КОЗЛЫ!" pattern).

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


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

"Никаких проблем" (с)


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

#12 
AlexNek патриот28.10.16 23:43
AlexNek
NEW 28.10.16 23:43 
в ответ moose 28.10.16 11:38
Т.е. по определению та же ф-я с теми же данными должна выдавать одинаковый результат

Определение нужно уточнить, что функция не должна при этом:

- иметь побочных эффектов.

- использовать другие классы/функции. В том числе и системные.


Когда он закончен и все тесты прошли - закомментирую

В этом и есть большой недостаток о котором и не задумываешся, пока нет CI.

Тесты должны идти после каждого коммита автоматом. Как то было, даже "полицейская" мигалка включалась при сбое, но в комнате были только программисты.


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

Бывает что всё работает без проблем в одной "среде", но при переносе в другую появляются проблемы. У меня на компе так часто бывало. На компе я меняю для чисел "немецкую запятую" на "привычную точку". И некоторые части проги это может приводить в ступор.

А для строк бывает достаточно сменить язык, чтобы "житроумный метод" накернулся.


не наш тест, который задает все время одни и те же тестовые строки, а жизнь закинет туда что-то такое, чего мы не ожидали

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

#13 
  moose местный житель28.10.16 23:59
NEW 28.10.16 23:59 
в ответ AlexNek 28.10.16 23:43, Последний раз изменено 29.10.16 00:00 (moose)

В конце-концов мы забываем, что мы вообще-то разрабатываем: тесты или что-то другое : ) Звоним клиенту: продукт - говно, но тесты - супер! И все проходят! Берите - не пожалеете!

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

- Вы программируете объекно-ориентированно (Вы применяете TDD/SCRUM/UT/...костыль №6)?

- Да, конечно!

- Это хорошо!

#14 
AlexNek патриот29.10.16 01:46
AlexNek
NEW 29.10.16 01:46 
в ответ moose 28.10.16 23:59
А если технология/методология входит в моду - каждый пыжится ее применить

Ну вообще то это самый фиговый подход.

Работал как то с одним, который любил обо всём новом читать и тут же это применять. Бо, сколько натерпелись....

#15 
Программист коренной житель29.10.16 07:57
NEW 29.10.16 07:57 
в ответ moose 28.10.16 23:59
По мне дак пока плотют - буду дома книги читать и вправы упражнять, а на работе - "как все".

Это ты зря ;) На работе должно быть интересно. Если стало не интересно, то надо уходить. ИМХО.


А если технология/методология входит в моду - каждый пыжится ее применить и об этом заявить клиенту.

Начнем с того, что клиенту пофиг на технологию :)

Ну если только это какой-то заказной софт и клиент выступает в роли Product Owner'а :) Не знаю случается ли такое, но почему нет?


Применять технологию из-за того, что это модно - это как минимум странно. Помню, когда у нис вводили скрам, то носились с ним все как золотым граалем из которого полезет совершенный код :) Люди реально верили, что технология менеджмента может как-то повысить качество создаваемого кода. Сейчас скрам у нас занимает около 20% рабочего времени :F при этом все как-то умудряются работать "по скраму", но при этом работа идет также как и раньше. Т.е. от скрама мы взяли только скучнейшие совещания ну и какое-то подобие планирования. Вообще у нас забавно получилось. На первом этапе роли продакт онера и скрам мастера совмещал наш тимлид :) Где-то через год нам назначили скрам мастера, но тимлид не сдает своих позиций :) и все также выполняет обе роли :D


#16 
bobkov постоялец29.10.16 23:37
bobkov
NEW 29.10.16 23:37 
в ответ moose 27.10.16 15:10
в общем, стоит ли всегда овчинка выделки?

По моему скромному мнению, надо покрывать Unit-тестами часто используемые функции (если в ООП, то классы). То есть, если в приложении есть какие-то слой "универсальных" сущностей, например, какой-нибудь модуль доступа к данным, то он должен быть хорошенько покрыт Unit-тестами. Если этого не сделать, то становится очень рискованно вносить в него какие-либо изменения, потому что много мест где он используется, что-нибудь да упустишь. На создание такого тестового покрытия уходит много времени - как минимум столько же, сколько на разработку самого работающего кода.

#17 
Программист коренной житель30.10.16 00:13
NEW 30.10.16 00:13 
в ответ bobkov 29.10.16 23:37, Последний раз изменено 30.10.16 17:56 (Программист)
По моему скромному мнению, надо покрывать Unit-тестами часто используемые функции (если в ООП, то классы).

Интересно, как определить это "часто"? Где граница?


Вот например такой код:

public interface Content
{
string GetContent(string path);
}

public class HttpContent : Content
{
public string GetContent(string url)
{
string content = null;

// Open connection

// download some information

// Close connection

return content;
}

public byte[] GetBinaryData(string url)
{
byte[] buf = null;

// Open connection

// download binary data

// Close connection

return buf;
}
}

public class DiskContent : Content
{
public string GetContent(string url)
{
string content = null;

// Open file

// read file

// Close file

return content;
}
}

public class SomeTool
{
public Content Content { get; private set; }

public SomeTool(Content content)
{
Content = content;
}

public string GetContent(string path)
{
return Content.GetContent(path);
}
}

public class SomeOtherClass
{
public SomeTool Tool { get; private set; }

public SomeOtherClass(Content content)
{
Tool = new SomeTool(content);
}

public string GetUserInfo()
{
return Tool.GetContent(@"some path\user");
}

public string GetFirmInfo()
{
return Tool.GetContent(@"some path\firm");
}

public string GetProductInfo()
{
return Tool.GetContent(@"some path\product");
}
}

Очевидно, что часто используемая функция тут SomeTool.GetContent (на нее идет целых 3 ссылки). Вот только надо ли ее тестировать? :)

Сдается мне, что оценка количества вызовов - неработающая оценка.

#18 
Murr_0001 знакомое лицо30.10.16 09:25
Murr_0001
NEW 30.10.16 09:25 
в ответ bobkov 29.10.16 23:37

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

И как раз в этот абстрактный слой не так давно внесены изменения.

Слой оттестирован - все методы работают как ожидается.

А вот все остальное - не работает. смущ Несмотря на то, что часть тестов там отрабатывают... но там покрытие в 0,5%...

#19 
  moose местный житель30.10.16 11:27
NEW 30.10.16 11:27 
в ответ Программист 30.10.16 00:13

Это у Вас случайно ни один из классов не наследует интерфейс Content, или так задумано. Если задумано, то поясните.

#20 
bobkov постоялец30.10.16 12:01
bobkov
NEW 30.10.16 12:01 
в ответ Murr_0001 30.10.16 09:25
Слой оттестирован - все методы работают как ожидается.А вот все остальное - не работает.

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

То есть, вот это утверждение "все методы работают как ожидается" не совсем верно. Как вариант, может быть, играет роль последовательность вызовов методов "слоя", которая раньше давала один результат, а после внесения изменений стала выдавать другой.

#21 
Программист коренной житель30.10.16 12:10
NEW 30.10.16 12:10 
в ответ moose 30.10.16 11:27

Забыл унаследовать :) Писал на коленке :) Но идея, думаю, понятна ;)

#22 
  moose местный житель30.10.16 16:36
NEW 30.10.16 16:36 
в ответ Программист 30.10.16 12:10

Это - не проблема: юнит тест мигом бы выявил : )

#23 
Программист коренной житель30.10.16 17:28
NEW 30.10.16 17:28 
в ответ moose 30.10.16 16:36

Это выявил бы компилятор :D

#24 
  moose местный житель30.10.16 17:41
NEW 30.10.16 17:41 
в ответ Программист 30.10.16 17:28, Последний раз изменено 30.10.16 17:42 (moose)

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

#25 
Программист коренной житель30.10.16 17:53
NEW 30.10.16 17:53 
в ответ moose 30.10.16 17:41, Последний раз изменено 30.10.16 17:56 (Программист)

Пробовать не буду :) Тебе придраться или как? Мысль заключалась в том, что некая функция используется дофига раз, а тестировать эту функцию смысла нет. Тестировать надо то, что, в данном случае, вообще ни разу не используется на прямую.


PS: добавил наслодование от интерфейса. вроде туда :D

#26 
  moose местный житель30.10.16 18:25
NEW 30.10.16 18:25 
в ответ Программист 30.10.16 17:53

Да это ясно: тестировать нужно только то, что имеет смысл тестировать.

Код зря корректировали: все равно никто не будет использовать : )

#27 
AlexNek патриот30.10.16 23:01
AlexNek
NEW 30.10.16 23:01 
в ответ Программист 30.10.16 17:53
Мысль заключалась в том, что некая функция используется дофига раз, а тестировать эту функцию смысла нет

Я бы взял аналогию с автомобилями - светофор раньше всего нужно ставить там, где они дофига ездят. А ставить его на выезде в поле, на окраине большого смысла нет.

"Вычислить" где делать, а где нет думаю не получиться. А вот знать где наиболее "важные" места в программе вполне можно.

#28 
Simple Nothing is f*cked31.10.16 13:54
Simple
NEW 31.10.16 13:54 
в ответ Программист 29.10.16 07:57

А кто сказал, что "тдд" и "интересно" обязательно идут нога в ногу? Мне вот иногда интересно какой-нить гейзенбаг найти :))

#29 
Программист коренной житель31.10.16 15:22
NEW 31.10.16 15:22 
в ответ Simple 31.10.16 13:54

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


У меня сейчас как раз такой момент :) Ухожу :D

#30 
Murr_0001 знакомое лицо31.10.16 15:42
Murr_0001
NEW 31.10.16 15:42 
в ответ bobkov 30.10.16 12:01

Вообще-то, Я поленился отквотить исходник в надежде что все и так будет понятно. Ну да ладно - вот "исходный постулат":

То есть, если в приложении есть какие-то слой "универсальных" сущностей, например, какой-нибудь модуль доступа к данным, то он должен быть хорошенько покрыт Unit-тестами.

Я привел тебе пример, когда 100% покрытие тестами этого "универсального" слоя не дает никакого полезного результата.

Тут же ты сам и говоришь:

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

Разумеется. Но 100% тест этого слоя этого факта не выявляет. Просто потому что это другой код.


может быть, играет роль

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

#31 
Simple Nothing is f*cked31.10.16 15:56
Simple
NEW 31.10.16 15:56 
в ответ Программист 31.10.16 15:22

Надеюсь, с прибавкой к зарплате? :)

#32 
Программист коренной житель31.10.16 16:00
NEW 31.10.16 16:00 
в ответ Simple 31.10.16 15:56

Не знаю еще :) Пока что я только сообщил шефу, что ухожу :) Пового проекта еще нет :D

#33 
Simple Nothing is f*cked31.10.16 16:04
Simple
NEW 31.10.16 16:04 
в ответ Программист 31.10.16 16:00

Ты ж фрилансер?

#34 
Программист коренной житель31.10.16 18:36
NEW 31.10.16 18:36 
в ответ Simple 31.10.16 16:04

Да. Сейчас вот ищу себе проект с 01.01.2017 :)

#35 
AlexNek патриот31.10.16 23:02
AlexNek
NEW 31.10.16 23:02 
в ответ Программист 31.10.16 18:36
себе проект с 01.01.2017

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

#36 
  moose местный житель31.10.16 23:08
NEW 31.10.16 23:08 
в ответ moose 27.10.16 15:10

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

#37 
AlexNek патриот31.10.16 23:12
AlexNek
NEW 31.10.16 23:12 
в ответ Murr_0001 31.10.16 15:42
но тесты "универсального" уровня этого выявить не могут.

Это мы просто тута только об одном уровне говорили.

В одном проекте было типа: внутри модульные, модульные и межмодульные.

Но в любом случае тесты не дают полной гарантии рабоспособности программы. Это всего лишь еще один дополнительный инструмент.

#38 
pavel-hh старожил01.11.16 04:52
pavel-hh
NEW 01.11.16 04:52 
в ответ Программист 31.10.16 18:36

а какие у вас требования и какие умения?

http://foren.germany.ru/arch/jobs/f/30833621.html?Cat=&pag...

для фриланса естественно другая оплата.

Linux is like a Wigwam. No Windows! No Gates! And Apache inside.
#39 
Simple Nothing is f*cked01.11.16 08:37
Simple
NEW 01.11.16 08:37 
в ответ pavel-hh 01.11.16 04:52
svn... DB2... Websphere

безум Жуть :)

#40 
Программист коренной житель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
NEW 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 
Программист коренной житель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
NEW 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 
Программист коренной житель10.11.16 11:38
NEW 10.11.16 11:38 
в ответ moose 10.11.16 10:28

Это все вопросы относительно предмета тестирования.

И даже в твоем примере нет необходимости в тестировании всей программы. Достаточно создать форму, подменить IsValid и сделать пару тестов, которые бы валидировали правильность связывания.


Но Вы говорите - не надо тестировать, там ничего не может пойти криво.

Я говорю, что WPF тестировать не надо :) Не знависимо от того, используется ли DynamicResource или StaticResource или button.Enabled = false - WPF в любом случае работает без ошибок.

#81 
Пирт гость10.11.16 18:26
NEW 10.11.16 18:26 
в ответ Программист 10.11.16 11:38

Может, уже не в тему мои 5 копеек, но сегодня вот пришло в голову: Agile нужен для того, чтобы продукт-оунеры/менеджеры ничерта не делали. В смысле, совсем ничерта, на каждый конкретный запрос "нам нужен детально проработанный сценарий/юзкейс/бэклог" отвечая "вот вам в общих чертах, остальное по ходу дела, ибо Agile. У вас же архитектура масштабируется? Тестами все покрыто? Вот и работайте, и не парьте меня своим планированием".

#82 
  moose местный житель10.11.16 23:14
NEW 10.11.16 23:14 
в ответ Программист 10.11.16 11:38

А никто не говорит, что тестировать нужно WPF. Тестировать нужно, работает ли Ваша фича. Правда, юнит тестом такого не протестируешь, и не то это место, где с юнит тестами нужно заморачиваться.

#83 
MrSanders старожил11.11.16 09:26
NEW 11.11.16 09:26 
в ответ Пирт 10.11.16 18:26
Agile нужен для того, чтобы продукт-оунеры/менеджеры ничерта не делали.

Не-а, делать им как раз постоянно что-то надо. Метаться между командой и "акционерами" (stakeholder)

вот вам в общих чертах, остальное по ходу дела, ибо Agile

В скраме не выйдет. В общих чертах добавить историю в бэклог - пожалста. Но пока не будет выполнено Definition of Ready (DoR) история а спринт не перенимается. На ревью проработали детально, тогда и программировать можно.


Неприятным сюрпризом для новообращенных скрамистов как раз таки становится количество времени, которое тратится на всевозможные планирования и согласования, тут тебе и пара ревью за спринт и ретроспектива и планирование спринта. А по идеологии во всем этом должна участвовать вся команда. Плюс скрам-мастер. У нас >25% (скорее 30%) рабочего времени скрам-команд уходят на всяческие совещания.


Планирование на ранней стадии - да, такого нет. Но определить "критерии качества" и "ограничивающие условия" (quality criteria, non-functional requirements) можно (и нужно для нового продукта) в т.н. "нулевом спринте". Архитектор(ы), product owner и stakeholder-ы должны определиться с "дорогими" (для изменения) вопросами.


Имхо, главная проблема agile вообще и scrum-а в часности это отсутствие понимания процесса у клиента.

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

#84 
Murr патриот14.11.16 11:53
Murr
NEW 14.11.16 11:53 
в ответ Программист 10.11.16 08:52

Собирался в тяпницу, но свалилась работа...


Зато будет неделька поискать решение...


Код - в аттачменте.

Методы, которые не получалось переработать следующие:

- loadDtStock_allBcds_loadInoiveNo_byOrder()

- loadDtStock_allBcds_loadInoiveNo_byLoad()

- loadRackNos()

может что и упустил.


Если интересует DXCR48 - могу запостить. Но там нет ничего интересного - строится СЯЛ-строка и результат возвращается как ДатаТабле.

#85 
Программист коренной житель14.11.16 15:29
NEW 14.11.16 15:29 
в ответ Murr 14.11.16 11:53
loadDtStock_allBcds_loadInoiveNo_byOrder()

Тут проблема только одна - DXCR48.loadDtInvoiceNo_byItem (...)

Я не знаю что это за функция, но ее надо закрыть заглушкой и тестировать так, как будто эта функция работает без ошибок.


Насколько я понимаю, DrOrder и DtInvoiceNo - это просто объект с данными, который тебе придется заполнять руками. Не могу сказать, понадобится ли тебе тут свой функционал.


loadDtStock_allBcds_loadInoiveNo_byLoad()

тут все также, как и в предыдущем случае - понадобится заглушка на DXCR48.loadDtInvoiceNo_byLoad(...) и DXCR48.loadDtInvoiceNo_byItem (...).

Единственное, что меня тут смущает - это DtInvoices.Compute(...) . Наверное придется таки делать обертку над DataTable.


loadRackNos()

тут самое интересное :)

DataTable таки придется подменить своей реализацией.

И при вызове DtStockOrderItems.Select() возвращать свои данные.



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

Это, конечно, не будет уже юнит-тестом, но возможно это будем разумным компромиссом. Это уже только ты можешь оценить.


Ну а DXCR48.loadDtInvoiceNo_byLoad(...) и DXCR48.loadDtInvoiceNo_byItem (...) надо будет тестировать отдельно. Я так понимаю, что это статические функции? Или DXCR48 - это синглтон?




#86 
Murr патриот14.11.16 16:25
Murr
NEW 14.11.16 16:25 
в ответ Программист 14.11.16 15:29

Тут проблема только одна

-----

Первая проблема в этом коде - то, что он не объектный. смущ


Насколько я понимаю, DrOrder и DtInvoiceNo - это просто объект с данными

-----

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



понадобится заглушка на

-----

Я чуток сошлюсь вперед - "Это, конечно, не будет уже юнит-тестом..." - Ну а раз ЭТО все одно не юнит-тест, то может и не надо заглушек? смущ

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

В общем делаю так - данные берутся из пром.базы и по ним считается "что там надо". Заодно отлаживается и конвертация СЯЛ - там изменения редки, элементарны, ошибки обнаруживаются почти сразу текущими тестами, отдельных тестов нет.



DataTable таки придется подменить своей реализацией

-----

Неее, не буду... во-первых - полную реализацию врапить долго. во-вторых - есть проблема - результат Селекта - ДатаРов-аррай - у меня врапируется в отдельный тип, который тестится. Этот тип имеет свой Селект. Точно такой же. И из-за этого Селекта там создается вторая таблица из которой и делается выборка. А это создает нерешаемую проблему - строки второй выборки - это не оригинальные строки из первичной таблицы. В общем - мне больше нужна правильная реализация Селекта для ДатаРов-аррай, чем полный враппер ДатаТабле. смущ



меня тут смущает - это DtInvoices.Compute(...)

-----

Это - самое простое - оно выносится в класс таблицы/субсета и там легко и просто заменяется на пересчет ЛИНКом... до тех пор пока не передается фильтр... с фильтром - труба... пока.



вместо этого сделать тестовую ДБ, и перед каждым тестом обнулять ее.

-----

Аккурат над этим сегодня сижу...

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


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

#87 
Murr патриот14.11.16 16:31
Murr
NEW 14.11.16 16:31 
в ответ Murr 14.11.16 16:25

В общем - мне больше нужна правильная реализация Селекта для ДатаРов-аррай, чем полный враппер ДатаТабле.

-----

Если кто знает где лежит оригинальный Селект - киньте ссылкой. Мне нужно чтобы исходный материал был ДатаРов-аррай, результат - ДатаРов-аррай, параметры - строковые.


Как вариант - автоконвертер из параметров в линк.

#88 
Murr патриот14.11.16 18:50
Murr
NEW 14.11.16 18:50 
в ответ Murr 14.11.16 16:31

Дописался...


------ Discover test started ------

========== Discover test finished: 83 found (0:00:00.4650465) ==========

No tests found to run.


смущ

#89 
Simple Nothing is f*cked18.11.16 13:17
Simple
NEW 18.11.16 13:17 
в ответ Программист 14.11.16 15:29

Читаю Ошерова (треть прочел). Пока что многовато того, что я уже знал (из книги Физерса, которую Ошеров тоже часто упоминает), но некоторые советы типа "только один мок на тест" уже наталкивают на правильные мысли. От .нет удается пока что успешно абстрагироваться :)

#90 
MrSanders старожил18.11.16 15:01
NEW 18.11.16 15:01 
в ответ Simple 18.11.16 13:17

В смысле "один мок на тест"? А если тестируемый метод получает два параметра и оба надо заменить моками?

#91 
Simple Nothing is f*cked18.11.16 15:12
Simple
NEW 18.11.16 15:12 
в ответ MrSanders 18.11.16 15:01

Вопрос в определении, что такое мок. Есть моки, стабы и фейки.

#92 
MrSanders старожил18.11.16 18:15
NEW 18.11.16 18:15 
в ответ Simple 18.11.16 15:12

Нда-с, посмотрел я что Ошеров называет моками.

The main thing to remember about mocks versus stubs is that mocks are just like stubs, but you assert against the mock object, whereas you do not assert against a stub.

Загнался он. Для меня моки по Фаулеру - "объект с запрограммированными ожиданиями".

#93 
  moose местный житель19.11.16 00:16
NEW 19.11.16 00:16 
в ответ Simple 18.11.16 13:17

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

#94 
Simple Nothing is f*cked20.11.16 16:03
Simple
NEW 20.11.16 16:03 
в ответ MrSanders 18.11.16 18:15

А мне нравится его классификация. Уже прикидываю, как я буду это прилеплять к своему легаси-проекту. Как раз написал для него gradle build, теперь можно и тесты делать потихоньку.

#95 
Simple Nothing is f*cked20.11.16 16:04
Simple
NEW 20.11.16 16:04 
в ответ moose 19.11.16 00:16

Ессно, для меня это имеет сугубо практическое значение.

#96 
MrSanders старожил20.11.16 22:14
NEW 20.11.16 22:14 
в ответ Simple 20.11.16 16:03
А мне нравится его классификация.

Слишком далеки они от народа (с). По крайней мере в яве. Все три основных фреймворка для создания "test doubles" (EasyMock, jMockit, Mockito) понимают под моками "объекты с поведением / ожиданиями". И все они позволяют "легким движением руки" собирать данные с помощью моков, чтобы их проверять. (т.е. одной строчкой превратить объект из стаба в мок).

#97 
Simple Nothing is f*cked21.11.16 13:24
Simple
NEW 21.11.16 13:24 
в ответ MrSanders 20.11.16 22:14

Вот, кстати, Фаулер: http://martinfowler.com/articles/mocksArentStubs.html

по-моему, вполне похоже на ошеровские выкладки. Все пока не читал, сохранил в инсту :)

#98 
MrSanders старожил21.11.16 14:11
NEW 21.11.16 14:11 
в ответ Simple 21.11.16 13:24

Чем же оно похоже-то? У Фаулера:

  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
  • Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Т.е. стабы это "заглушки". Программируем то что надо, что не надо оставляем пустым, где надо что-то собрать - храним. Моки - "имитаторы", декларируем поведение для вызовов - тут верни 1, тут брось эксепшен.

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

#99 
Simple Nothing is f*cked21.11.16 14:23
Simple
NEW 21.11.16 14:23 
в ответ MrSanders 21.11.16 14:11

Ну так точно как оно и у Ошерова. То есть, мок нужен, чтобы доказать, что вызов метода был, а стаб - чтобы вернуть нужное значение или протестировать состояние.

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

MrSanders старожил21.11.16 15:11
NEW 21.11.16 15:11 
в ответ Simple 21.11.16 14:23

Ну дык я ж копировал цитату Ошерова из сети:

The main thing to remember about mocks versus stubs is that mocks are just like stubs, but you assert against the mock object, whereas you do not assert against a stub.

И в примере было что в объекте собираются данные, а потом ассертом проверяются.

а стаб - чтобы вернуть нужное значение

Не-а, моком тоже могу вернуть нужное значение. Разный подход. В стабе мы имплепентируем метод, а моку говорим "у тебя вызовут divide(4,2) а ты вернешь 10".

  moose местный житель21.11.16 18:15
NEW 21.11.16 18:15 
в ответ MrSanders 21.11.16 15:11

По-моему, это стаб создается для того, чтобы вернуть значение. Причем "правильное", которое нужно для того, чтобы прошел наш тест. И мы проверяем, получили ли мы В ТЕСТИРУЕМОМ ОБЪЕКТЕ ожидаемый результат. А мок создается, чтобы проверить, правильно ли тестируемый объект общается с внешним миром. И проверяем мы это не в тестируемом объекте, а В МОКЕ, правильно ли наш объект с ним общался (вызывал, посылал данные, сообщения, ...)

Simple Nothing is f*cked23.11.16 23:18
Simple
NEW 23.11.16 23:18 
в ответ moose 21.11.16 18:15

нп

Сегодня пытался запулить первый тест с JMockit. Приватные методы, статические инициализаторы, remote ejb call. Короче, все дела. Не получилось :(

MrSanders старожил25.11.16 15:01
NEW 25.11.16 15:01 
в ответ Simple 23.11.16 23:18

Приватные методы это и статическая инициализация это да, больно. Если нельзя менять код, то может помочь PowerMock

Если надо "замОчить" приватный, статический метод или даже конструктор. Баловство с байткодом и класслоадерами.

А вот вызовы Ejb можно подменить. С помощью reflections можно переписать значение даже финального поля. Подменишь Factory на свой мок - и вперед.

Simple Nothing is f*cked25.11.16 15:17
Simple
NEW 25.11.16 15:17 
в ответ MrSanders 25.11.16 15:01

Я уже разобрался с JMockit.

Комбинация мокапов с "ожиданиями" довольно мощная.

public class VOCreaterTest {
@Mocked
private BenutzerVO benutzer;

@Test
public void createVO_Vorgang() throws Exception {
new MockUp<ObjectCacheSingleton>() {
@Mock
public synchronized CacheEntry getCachedObject(ObjectKey key) {
if (key.getKey().equals(CacheConstants.KEY_LIST_VORGANGSTATUS)) {
CacheEntryImpl entry = new CacheEntryImpl();
FKValue fk = new FKValue();
fk.setKey(CacheConstants.VORGANGSTATUS_OFFEN);
entry.setObject(fk);
return entry;
}
return new CacheEntryImpl();
}

@Mock
public void initializeCachedObjects() {
}
};

new MockUp<ObjectmanagementUtil>() {
@Mock
public VorgangVO loadVorgangDaten(VorgangVO vorgang, String schadenId, FKValueWithSchadenschluessel beteiligtenrollen, FKValueWithSchadenschluessel fahrzeugrollen, String messageAlle) {
return null;
}
};

new MockUp<Logger>() {
@Mock
public void debug(Object message) {
}
};

VOCreater creater = new VOCreater();
VorgangVO vo = (VorgangVO) creater.createVO(SamVO.VO_TYPE_VORGANG, null, benutzer);
assertTrue(vo.isOffen());
}

@Test
public void createVO_Schaden() throws Exception {
new MockUp<ObjectCacheSingleton>() {
@Mock
public synchronized CacheEntry getCachedObject(ObjectKey key) {
return new CacheEntryImpl();
}

@Mock
public void initializeCachedObjects() {
}
};
VOCreater creater = new VOCreater();
SamVO vo = creater.createVO(SamVO.VO_TYPE_SCHADEN, null, benutzer);
assertTrue(vo instanceof SchadenVO);
SchadenVO schadenVO = (SchadenVO) vo;
assertNotNull(schadenVO.getSachbearbeiter());
}
}

Правда, у автора похоже clean code головного мозга, а развитие фреймворка идет в сторону чистого тестирования.

MrSanders старожил25.11.16 17:13
NEW 25.11.16 17:13 
в ответ Simple 25.11.16 15:17

Какой молодец. Кто б еще PowerMock зарезал бы...

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

Скоро потребуют им свою JVM написать. Для тестов, ага. Тесты ведь для того и нужны чтобы найти плохой код, который надо переписать.

Если ты его даже протестировать не можешь, как ты его расширять / модифицировать будешь?


Наши уже доигрались. В 8-й яве улучшили JIT, он теперь распознает статические методы, возвращающие значение static final-а

и при определенном количестве вызовов тупо подменяют в коде вызов на значение поля. Измениться-то оно не может, final же.

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

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

А отключать инлайниг полностью не вариант - тесты в 4-5 раз дольше работают.

Слава богу я хоть использование PowerMock-а у нас сделал настолько неудобным, насколько можно. А то бы еще и из-за приватных методов мозги клевали бы постоянно.

Simple Nothing is f*cked25.11.16 17:16
Simple
NEW 25.11.16 17:16 
в ответ MrSanders 25.11.16 17:13

Так любым инструментом можно себе ногу отстрелить. А что прикажешь делать, когда нужно старье допиливать, а тестов нет вообще?

MrSanders старожил25.11.16 17:42
NEW 25.11.16 17:42 
в ответ Simple 25.11.16 17:16

Допиливать подразумевает править код, верно? Вот в процессе написания тестов и правь. Видишь доступ к чужому синглтону, спрячь за своим get-ом.

Вместо

EjbFactory.getInstance().getBean()

будет у тебя

protected EjbFactory getEjbFactory(){ return EjbFactory.getInstance();} и getEjbFactory().getBean() вызов.

Всё. Хочешь - в подклассе переопределяй, хочешь в моке эмулируй.

Simple Nothing is f*cked25.11.16 17:46
Simple
NEW 25.11.16 17:46 
в ответ MrSanders 25.11.16 17:42

Допиливать подразумевает не трогать лишнего :)

My problem is that the real world is not just about good code. One is often facing a ugly old codebase where you need to fix that one special bug and then leave the rest behind.
You neither have the time nor the intention to fix all those design and structural issues that where made in the past, but you want to get a basic feeling that your bugfix might work in production too.
So you mock as much as possible, isolate the problem, fix it and leave the test there so no one else will break it again.
MrSanders старожил25.11.16 18:09
NEW 25.11.16 18:09 
в ответ Simple 25.11.16 17:46

Угу. Только на написание такого теста уходит в два раза больше времени чем на правку кода, а потом ошибки лезут в тестах чаще раз этак в 100 чем а тестируемом коде.

У нас такое есть. Чтобы тестировать создание страховых случаев полсистемы моками меняем. А потом каждую неделю правим моки. Потому что то в одном модуле выбросили приватное поле, то в другом поменяли количество параметров у приватного же метода. TCO для таких тестов лучше не считать.

Я только в одном классе (фейк доступа к одному типу классов) только за последний год несколько десятков!!! правок делал. И каждая стоит время. Часа 2-3 пока поймешь что изменилось и что теперь можно сделать. Половину системы перевели на DI и расзод времени на правку тестов упал до незаметного, а у второй половины...

У команды "нет времени". А тесты править каждую неделю и выть часами на совещаниях что мы им должны вынуть и положить кнопку "поправь тест за меня" - есть.

Simple Nothing is f*cked25.11.16 18:12
Simple
NEW 25.11.16 18:12 
в ответ MrSanders 25.11.16 18:09

Ты прав. Я все равно собирался покрывать тестами только те части, которые буду трогать, а там уже и рефакторить можно/нужно.

Murr_0001 знакомое лицо30.11.16 19:45
Murr_0001
NEW 30.11.16 19:45 
в ответ Simple 25.11.16 18:12

NP.


MS Tests.

Интеграционные тесты.
Для выполнения тестов необходимо иметь разные наборы данных в базе (Оракле).

Имею код, создающий в тестовой базе нужные таблицы.

Имею несложный код заполняющий базу нужными данными.


Работает так: при инициировании теста создаются задействованные таблицы, туда

вгоняются данные, отрабатывает тест, все дропается.


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

Имеется в виду не процессорное время для вбивания данных и выполнения теста,

а время на подготовку скриптов вбивания данных.

При этом данные из базы извлекаются уже в виде полуготового скриптового кода.

Т.е. Я получаю строку вида table,AddRow(1, 2, 3, "", DateTime.Parse("24/12/206"));

дальше - копипасте и фиксинг неправильных параметров.


Есть какая методика по упрощению процесса?


daduda Забанен до 21/7/25 15:44 постоялец17.12.16 21:49
daduda
NEW 17.12.16 21:49 
в ответ moose 27.10.16 15:10

ОК, ставлю вопром ребром: где найти в Германии ацуби, который бы написал бы тесты (не обязательно юнит-) с использованием всех паттернов, описанных в книжках месароша и искусстве автономного тестирования.


Ну и этот ацуби мог бы хотя бы после курсов Баранцева написать пару автотестов для крупного сайта. С использованием PageObject паттерна, да


Ключевое слово здесь - ацуби. Т.е.он должен иметь доход уровня Hatz-IV-щика и жить у родителей.

MrSanders старожил18.12.16 13:13
NEW 18.12.16 13:13 
в ответ daduda 17.12.16 21:49

Нигде. Только сделать самому. Берете себе на фирму ученика (или студента на 10 часов в неделю) полгода - год учите, потом пользуетесь.

1 2 3 4 5 6 все