Комментарии 27
Последние полгода ... За это время я написал более 500 юнит-тестов ... учетом того, что бизнес-задачи продолжали выполняться
Не верю!!! (с) Станиславский .. 5 тестов в рабочий день (возможно по неизвестной области) ...
Либо это жёская галера ...
Это сарказм? Посмотрел свою статистику в сонаре - 950 тестов с начала 2023 года. Это же юниты. Они по самой идее маленькие, простые и многочисленные.
Юнит-тесты очень просты и состоят обычно из трех строчек кода:
assign
act
assert
К тому же в 80% случаев Ваши тесты будут копиями друг друга, но имеющими лишь отличия в третьей строчке, т.е.в том условии, которое Вы проверяете.
Согласитесь, что написать 5 функций, состоящие из 3-х строчек в день вполне возможно. Я даже удивляюсь, что написано всего 5 тестов в день, а не существенно больше.
Да, интеграционные тесты будет написать чутка сложнее, но и они должны состоять лишь из 4-х строчек (в первом пункте будет 2 строки, вместо одной, т.к. нужно создать 2 объекта и проверить их интеграцию). Тоже, кажется, что можно писать существенно больше 5 тестов в день.
e2e-тесты еще сложнее, но и они пишутся из заготовок и уже не проверяют то, что было проверено в двух абзацах выше. В итоге, даже тут 5 тестов в день выглядят прям скромным результатом.
Если у Вас так не выходит, задумайтесь, где Вы ошибаетесь.
Эмм, простейшие тесты пишутся пачками легко. Условно, день чтобы обложить небольшой модуль как минимум 3-4 десятками тестов - вообще без проблем.
Как уже сказал @ws233 тесты часто похожи, например, если у нас есть два сервиса суть которых только делать запрос на бэкенд, но с разными url-ами, то их тесты будут практически копиями. Также часть тестов могут быть параметризированными, если считать их за несколько. А некоторые тесты делаются копированием, например, если проверяем функцию, которая на вход может принять строку, null и undefined, в таком случае два последних кейса будут копией, только разные входные аргументы.
Могут быть и сложные legacy-моменты, когда проще переписать код и только потом написать тесты, или же при написании тестов зависимости настолько запутанны, что их невозможно замокать. В таких случаях написать 5 тестов за день может быть рекордом, но в остальных случаях, можно запросто написать 15-20 тестов без проблем.
Реальный диалог в одной конторке федерального уровня торгующего электроникой и телефонами с материнской зелёным опсосом:
Финансовое приложение через которое проходят десятки тысяч покупок в день.
0% покрытия тестами.
Отдельных тестировщиков нет.
Разработчик: надо писать тесты, юнит, интеграционные, e2e, а то на проде что-нибудь вылезет с оплатами и компания потеряет миллионы всего лишь за пару минут простоя.
Тимлид: ну надо, да...
Разработчик пишет тесты
Менеджер: какого фига задача так долго делается?
Менеджер Менеджера: какого фига задача так долго делается?
Тимлид: что с задачей?
Разработчик: ну вот, тесты, замокать не всё можно, надо покрыть API, интеграционные тесты сделать, нагрузочные... чтобы код был качественный, прод не упал и компания бы не потерял 100500 миллионов из-за простоя.
Сеньор-пополиз: кто тебе говорил писать тесты? Этого нет в задаче!
Менеджер, тимлид и техдер: Разработчик, ты уволен!
Разработчик: Окай.
--------------------------------------------------
Другой подобный диалог в американском стартапе получившим 20 миллионов долларов инвестирований:
1% покрытия тестами.
Тестировщиков в штате нет.
Разрабочик: давайте тесты напишем? Сделаем тестовые сервера промежуточные? Контейнеры сделаем?
Тимлид: Нет.
Менеджер: Нет. У нас и так задач дофига.
*"Разрабочик сделал задачу и отправил на ревью сеньорам и тимлиду".
Сеньор: Всё ок, утверждено.
Тимлид: Всё ок, утверждено. Сразу заливаю в продакшен.
Продакшен нагинается. Клиенты начинают звонить.
Техдир: какого фуя, что ты наделал, разработчик? Это твоя ответственность!
Разработчик: вот, выяснил, у вас в проде версия библиотеки отличается на одну минорную!
Директор: ты должен был это проверить!
Разработчик: У меня доступов нет до продакшена - я не знаю что там крутится. Да и я предлагал писать тесты и сделать тестовые интеграционные сервера, а не лить сразу в продакшен...
Директор: не ипёт. Ты уволен!
Разработчик: Окай.
Тесты – это не просто документация. Это 100% копия технического задания, переведенная с человеческого на язык машинных кодов. Если у вас есть тест, но нет соответствующего описания на человеческом языке в ТЗ, то стоит это описание туда добавить. И наоборот. Любое изменение в ТЗ приводит к гарантированному изменению в тестов. В итоге у вас 1 и тот же документ записан на двух языках: человеческом (ТЗ) и машинном (тесты) – и оба перевода должны постоянно синхронизироваться в обе стороны.
Проблемы с покрытием у Вас из-за отсутствия изоляции. Изоляция – необходимое условие юнит-тестов (принципы FIRST). Если вернете им изоляцию, то проблем с подсчетом покрытия для них не будет. С интеграционными и e2e-тестами это не сработает. Там изоляция быть не может, а значит, что и покрытие для этих тестов как метрика быть использована не может. Другими словами – покрытие можно считать ТОЛЬКО для юнит-тестов (которые являются копией ТЗ, помните?), для всех других тестов эту метрики использовать нельзя.
Если вам легко читать код и легко его дорабатывать, это не значит, что его легко покрыть тестами.
В правильной архитектуре любой код легко покрыть тестами. Если у вас это не так - наймите правильного архитектора. По вашему примеру, это могло бы выглядеть как-то так, без ручной возни с двойными инициализаторами (в конструкторе и в ngOnInit):
export class UserComponent extends IoC {
@mem user() {
reurn this.$.get( UserService ).getUser()
}
}
Но если вам легко написать на код тест, скорее всего, он легко читается и у него простая логика.
И скорее всего он не делает ничего полезного, а вся сложность предметной области переехала в область взаимодействия между модулями.
я написал более 500 юнит-тестов, а тестовое покрытие удалось увеличить примерно на 30%
А могли бы написать 50 компонентных тестов и увеличить покрытие до 99%: https://page.hyoo.ru/#!=2jggfw_at1ily
PS: дизайнер, который рисует грязно жёлтым по мрачно серому, кажется пытается сказать нам: "Спасите меня отсюда, меня держат в заложниках и заставляют рисовать унылые картинки!".
Сейчас выскажу непопулярное мнение: тесты - это побочный артефакт разработки, совсем не ее ЦЕЛЬ. Поймите это наконец. Чем больше тесты отнимают времени и ресурсов, тем выше оверхед вашего подхода к процессам и ниже их эффективность. Часто тесты - это просто попытка снять с себя ответственность. Тесты - это условность, и очень часто, множество кейсов реального использования пересекается со множеством тест-кейсов весьма... незначительно. Иначе в энтерпрайз приложениях никогда не было бы багов. И чем сложнее ваша система, тем этот эффект проявляется более явно. Идеально покрыть тестами сложный код - просто математически невозможно. Соответственно, вы всегда должны понимать где пора остановиться и где более применимы принципы хаос-инжиниринга. Код нужно писать не так, чтобы его было легко тестами покрывать, а так, чтобы максимально снизить стоимость последствий возможной ошибки и максимально удешевить, упростить и ускорить ее исправление.
Я сейчас не утверждаю, что тесты писать не нужно совсем, я увтерждаю, что делать из них религию - ОЧЕНЬ вредно.
Как на счёт стратегии покрывать тестами только баги - которые уже вылезли на продакшене или тестировании? Т.е. флоу такой:
- пилим себе "свободно" проект\фичу
- выкатываем в тест\прод среду, он там крутиться
- споймали баг, пофиксили, покрыли его тестами
- и так на протяжении всей жизни проекта
Т.е. да, скорее всего юнит-тестов может не будет вообще, потому что в основном падать будет где-то на пограничных слоях системы.
Тогда будут покрыты реальные кейсы, а не вымышленные ветрянные мельницы. Кажется разумным компромиссом, между не писать тесты вообще, и писать упорно на всё "подсознательно страдая от бесполезности".
Полностью согласен с тем, что тесты - это не цель разработки и, тем более, не религия. В статье я хотел сказать, что тесты - это инструмент, который помогает совершать меньше ошибок, и им нужно научиться пользоваться.
Покрыть тестами полностью приложение нельзя, и большим ограничением, чем математика, выступают сроки и требования к системе. Если пишем прошивку для самолета или кардиостимулятора - нужно больше тестов, если у нас лендинг - ему тесты могут и вовсе не нужны. Если же требования допускают вольность, то тут стоит обратиться к договоренностям, чтобы тесты или их отсутствие не стали проблемой
Идеально покрыть тестами сложный код - просто математически невозможно.
Математика очень не любит, когда ей приписывают слова, которых она не говорила. :)
Поглядите, пожалуйста, мутационное тестирование. Оно как раз и отвечает на вопрос, а сколько багов из тех, что можно вообще допустить в вашем коде, Вы вылавливаете вашими тестами. Раздел математики – комбинаторика – дает четко однозначный ответ, как это все посчитать и сколько вообще ошибок может быть.
Да, религию делать не надо, но получить вполне себе однозначную качественную оценку вашей сколь угодно сложной системы вполне возможно. И математика Вам в этом поможет.
Тесты - документация - кмк это маркетинг буллшит. Есть примеры решения реальных юзкейсов?
Как какой-нибудь не-QA решил получить какое-то значение о продукте и для этого полез в репу с тестами, нашел там нужный текст и из него понял бизнес-подоплёку?
нашел там нужный текст и из него понял бизнес-подоплёку
А что именно вам тут кажется невероятным? В инструментах вроде кукумбера у каждого теста есть текстовое описание типа "подаем на вход А - получаем на выходе Б" или "подаем на вход Г - получаем ошибку". Если это не документация, то что? Та же история на более низком уровне юнит-тестов.
Вы привели пример приемочного тестирования, тут вопросов нет. Можно подробнее про "ту же историю" только в рамках юнит-тестирования.
Иногда нужно понимание того как А или В следует понимать в рамках более общего бизнес процесса. Сферический код в вакууме как и тесты к нему скорее всего не будут интересны.
Я не пойму, в чем ваш тезис? Есть некий процесс Х. На процесс написан тест. Из теста понятно, что делает процесс Х при тех или иных входных параметрах. Всё - это документация. Нравится это кому-то или нет, полезна ли она лично вам или нет - но оно вот так работает.
Если тест не помогает понять на более высоком уровне, как процесс работает с другими процессами - так он и не должен. Документация на тормозной диск помогает вам 100% понять, как работает вся машина? Нет, и это было бы абсолютно бредовым требованием.
Именно бизнес-полопёку лучше получать из интеграционных тестов, или е2е-тестов, так как они отображают юзер-кейсы. А вот суть того, как работает конкретный метод/функция можно узнать из юнит-теста. Конечно, в первую очередь стоит смотреть на документацию/ТЗ и на сам код. Самый частый кейс, когда тест рассматривается в качестве документации, если он упадет, тогда описание теста как раз скажет, как работал код.
Так во том-то и дело:
"конкретный метод/функция можно узнать из юнит-теста".
"Ок, пишем тесты так, что "подаем на вход А - получаем на выходе Б". Готова документация для другого разработчика.
Это как раз теория, что тесты это дока. Никто ж с ней не спорит. Вопрос - использует ли кто-то такой подход в компаниях? Для опенсорс-проектов - да, частенько заглядываю в тесты и получаю ответы (впрочем, ещё чаще просто в код).
А вот on-premise... Я как-то пытался понять, как у нас в продукте JWT токен генерится. Но не смог продраться сквозь классовые навороты модного тестового фреймворка на котлине ( Пришлось тупо спрашивать голосом.
Вопрос - использует ли кто-то такой подход в компаниях?
Кто-то пользуется, кто-то нет. Мы пользуемся. Пилим очень даже коммерческий и проприетарный продукт. Для выяснения таких нюансов как раз и существует секция "ваши вопросы" на собеседованиях. Кто-то на ней выясняет, как в компании амазоны кубернетятся. А кто поумнее - спрашивает полезные вещи в том числе про практики тестирования.
Кроме того, никто не запрещает вам приобрести субъектность и самому задавать тренд на культуру тестирования.
Приветствую! Спасибо за статью !
Один тест все же не дописали.
Кейс: заходим в МП тинькофф
1.Платежи
2.По номеру телефону
3. Вставить из буфера обмена телефонный номер формата +7xxx xxx xx xx
4. СОВПАДЕНИЙ НЕТ (ЭКРАН ПУСТ )
5.Жмакаем на крестик. Повторяем п.3
6.СОВПАДЕНИЕ НАЙДЕНО .ЮЗЕР И ФОРМА ПЕРЕВОДА ДОСТУПНЫ
Android v.13
Kernel 5.10.136
Приветствую! Спасибо что заметил баг и не промолчал! Я передал его команде разработки мобильного приложения.
Рекомендую заводить баги через чат поддержки или через обратную связь в мобильном приложении, так точно он попадет к разработчикам раньше)
Ещё б денег за это давали, а то экономия на тестировании даёт о себе знать. Особенно в той части собеседования, где говорят, что у вас нет тестировщиков, которые кейсы пишут и отрабатывают. Писать автоматизацию хрен пойми на чём и как - хреновая идея.
Я - пользователь. Я не хочу ждать исправления. Я и так деньги у вас держу. И функционал должен работать на три девятки.
Извините, если, написав много тестов, следуя хрестоматийным TDD-шным истинам, в вас не закралось зерно сомнения по поводу правильности данного подхода, то вы пока еще ничего не поняли.
Тесты — это документация
Буллщит. Покажите мне хоть один проект, где бы документация была опубликована ввиде тестов. Есть конечно BDD, но это когда тесты готовят по опубликованной спеке, а не наоборот. Простая и понятная сигнатура метода -- сама себе документация. Для неочевидных вещей здесь же описывается спека на человечьем языке. А ваши стопицот тестов никто никогда не прочтет в жизни.
Но если вам легко написать на код тест, скорее всего, он легко читается и у него простая логика.
TDD и злоупотребление unit-ами ведет к излишней фрагметнированности кода, когда логика становится "размазанной" по большому числу абстракций и фунциональных компонентов, созданных искусственно в угоду тестируемости. В итоге каждый фрагмент действительно становится проще тестировать отдельно, но вся композиционная логика бизнес кейса остается за пределами какого-то либо теста, что зачастую провоцирует "нежданчики" на проде. И понять что реально делает фрагментированный код на порядок сложнее, нежели если вся логика была бы описана линейно.
Другая вещь, которую вы не упомянули -- это мокирование. Оно как правило занимает 90% времени написания теста и его отладки. А самое смешное, что в подавляющем большинстве случаев поведение мокированного кода -- это поведение сферического коня в вакууме, которое слабо соотносится с реальными кейсами. Особенно все, что касается стейта и базы данных. Поэтому народ сейчас все более склонен поднимать в контейнере реальную базу с тестовым набором данных, чтобы тестировать все как есть. А юниты все чаще заменяются "сценарными" тестами, которые тестируют именно бизнес спецификацию, а не внутренний дизайн.
у компонента есть шаблон, взаимодействие с которым нужно тоже протестировать, и хуки жизненного цикла, которые накладывают дополнительные ограничения в тестах.
Совершенно верно, и это проблема Angular и других фреймворков, которые местами противоречат вашему тезису о тестируемости кода, вынужная вас строго следовать исключительно предусмотренным паттернам.
Давайте немного улучшим наш код. Перенесем логику в сервис
Это по-вашему улучшение? Вы нагрузили сервис доступа к данным инородной логикой обработки и визуализации ошибки, закамуфлировав ее ввиде "пустого" результата для компонента.
Тесты — это инвестиции в светлое будущее
Тесты -- это мусор в проекте, необходимый лишь для повышения качества service delivery, и требуют значительных затрат на написание и поддержку. Чем больше глупых тестов в проекте с многократным покрытием одних и тех же фрагментов, тем сложнее становится выкатывание новых фич. Поэтому держать нужно лишь необходимый минимум.
Тесты -- это тоже код, поэтому они также могут содержать баги. Кто же тестирует тесты? Основной код? Круговая порука получается.
Что я понял, когда написал много тестов