
Пока оперативка дорожает из-за LLM, в банках очень много ручного тестирования. Покрытие автотестами не очень высокое, потому что их тоже надо писать с AI, а ИБ закономерно запрещает доступ к внешним облачным моделям. Мы не можем просто взять закрытый код банка и скормить его публичной нейросети.
По большей части на ручные тесты уезжают сверка логики процесса (end-to-end-сценарии) и тесты UI.
Я работаю в команде Centicore, но мы сидим на стороне клиента — крупного банка — и занимаемся разработкой в его закрытой среде. То есть мы наёмная команда на продукте заказчика.
Сейчас я хочу рассказать про несколько довольно странных багов из разных приложений. В силу тех самых требований ИБ я даже названий банка и проектов раскрыть не могу, но в деталях покажу, какие бывают приколы. Например, когда вы пересаживаете приложения с айфона на планшет.
Промокод, который невозможно ввести
Медицинское приложение. Изначально не было разбивки на команды: одна большая группа пилила и веб, и мобилку (iOS, Android), и бэкенд. Негласно было так: один тестировщик глубже сидит в вебе, другой — в мобилке, третий лучше шарит за бэк. Но дейлики общие, ретро общие, груминги — всё общее.
Потом появились специализации, и вот в этом месте оказалось, что заложен первый кирпич для возможной потери контекста, потому что пропал полный end-to-end. Точнее, он разбит на итерации.
Врач сидит в государственной клинике за компьютером, ему нужен веб — это стационарное рабочее место. Пациент может быть в дороге, на работе, на даче — где угодно, и ему нужна мобилка.
Пациент через приложение отправляет замер: давление, уровень сахара в крови, данные о качестве сна, бессонница, храп — в общем, показания, которые для него важны. Всё это проходит через Kafka, через микросервисы и отображается у врача в вебе. Доктор смотрит данные и назначает терапию: тыкает кнопку, выбирает лекарство и его дозировку. Пациент видит назначение у себя в мобилке.
В какой-то момент стала нужна функциональность промокодов. Пациент получает промокод, активирует его, и ему подключается подписка на мониторинг врача, например, по артериальной гипертензии на месяц или на три. «Нужно это вчера» — прямая цитата, сроков фактически нет. Аналитик вернулся в прошлое и написал спецификацию. Разработчики сделали ровно то, что было написано. Ни больше ни меньше.
Фичу делали в две итерации. Первая: в веб-интерфейсе врач или администратор клиники (либо целого региона) может создавать промокоды. Вторая: в мобильном приложении пациент может их активировать.
Прикол в том, что поле для ввода пациентом промокода покрывалось требованиями (валидацией), а форма для создания промокода — нет. Создать можно было что угодно: кириллицу, латиницу, пробелы, кавычки, восклицательные знаки — хоть 300 символов. Можно было написать название больницы, имя врача, теоретически даже SQL-инъекцию (я, правда, не проверял на проде). При этом промокод состоял из двух частей: префикс — его вводил врач руками, это и было поле без валидации — и автоматически сгенерированный бэкендом хвост с UIN. То есть промокоды выпускались не по одному, а пачками — обычно по сотне за раз.
А в мобилке вводить можно максимум 20 символов: только латиница, без пробелов, без спецсимволов, без кириллицы.

Представьте, что администратор клиники садится за веб, создаёт промокод с русским префиксом — скажем, «АвИцЕнНа» или «Бахилы» — и выпускает пачку в несколько сотен штук. Промокоды уходят пациентам. Пациент открывает приложение, вводит промокод — приложение показывает ошибку: «В промокоде нельзя использовать кириллицу».
Если бы я подошёл к тестированию формально, то всё выглядело бы идеально. На вебе — всё по документации первой итерации. На мобилке — всё по документации второй итерации. 20 символов? 20. Русские. Валидируются? Валидируются. Зелёный свет, фича — в прод.
А потом в реальной жизни встречаются врач с пациентом, и система ломается на стыке двух платформ, которые разрабатывались в разное время и с разными требованиями.
Если бы я не прошёл реальный пользовательский флоу — было бы очень плохо. Потому что сотни пациентов страдали бы молча, приложение формально работало бы, а подписки на мониторинг просто не подключались бы. Дальше — объяснения с государственными клиниками, пересоздание промокодов, экстренный фикс. Причём не генерации (она уже сделана) — фиксить надо именно приложение. И вот тут — второй уровень боли: быстро починить мобилку — это не быстро. Мобильное приложение — всегда узкое горлышко, потому что существует жёсткая зависимость от релизных циклов. На тот момент приложение было полностью нативным, без динамических обновлений. Многие крупные игроки к тому моменту уже перешли на динамику — примерно за полтора года до этого, когда все носились с обходом сторов. А это приложение — нет. Для хотфикса это означало полный цикл: собрать сборку, отправить на ревью в App Store и Google Play, дождаться одобрения, опубликовать. А пациенты тем временем не могут подключить мониторинг давления.
К счастью, вовремя нашли.
Звёзды, которые меня нереально достали
Стандартная фича VOC для финтеха — Voice of Client, то есть обратная связь от клиента приложения. У нас есть всякие оценки удобства разделов приложения, оценка консультаций в чате плюс все чаты целиком — чат с поддержкой, чат с менеджером, чат с персональным брокером — и пуш-уведомления.
Коллега, который вёл эту фичу, ушёл на больничный.
Начинаю тестировать — и вижу дичь: нажимаю на одну звезду — выбираются две. Нажимаю на две — выбираются три. Всегда на одну больше. Свайпом — то же самое: ведёшь пальцем до области третьей звезды — оп, подсвечивается четвёртая. Доводишь до четвёртой — выбрано уже пять.
Первая мысль: я что-то делаю не так.
Отдаю коллегам: «Посмотрите, как у вас». У них всё работает идеально. Начинаем исключать переменные. Версия ОС? У всех — Android 15. Тестовый пользователь? Один и тот же. Сборка? Идентичная. Вообще всё одинаковое, а результат разный. Может, экран глючный? Нет, только тут.
Затащить ещё один тестовый телефон в контур финтеха сложно, но мы сделали. Короче, спустя некоторое время странная гипотеза подтвердилась: баг воспроизводился только на Самсунгах. На эмуляторах — нет. На других марках — нет. Только на живом железе Самсунгов.

Вот функция «Отображать касания» — она живёт в меню для разработчиков — я записал видео. На экране чётко видно: красная точка касания стоит на одной звезде, а подсветка — уже на следующей.
Выкатить фикс было очень сложно: было нужно реальное железо — эмуляторы не покрывали. Баг опасный: потом были бы мемы про то, что если кто-то ставит три звезды, система переправляет на четыре.
Почему так мало железа? Потому что в структуре команды — три устройства на одного тестировщика. Тестировщиков много, а зоопарка устройств мало. Да, Андроиды разные, но не так чтобы прямо сильно. Мы физически не потянули бы тестирование на большом парке. Одно регрессионное тестирование — это порядка тысячи тест-кейсов только у нашей команды. Регресс длится около двух недель — это уже тяжело пройти на одном устройстве. Если бы каждый тестировщик проходил регресс ещё и на куче разных девайсов, то мы занимались бы исключительно регрессом и больше ничем. Автоматизировать, повторюсь, мы не можем из-за требований службы безопасности банка.
Вообще, если сравнивать платформы, то iOS — это удовольствие. Apple унифицировали экосистему настолько круто, что ситуация, когда на iPhone 13 баг есть, а на iPhone 15 его нет, — это почти невозможно. Android — полный мрак. Особенно если брать Huawei без Google-сервисов: на этих устройствах, например, пуши — это вообще отдельный разговор и головная боль.
Но у Apple есть одна граница, на которой что-то может сломаться: iPhone и iPad. Пример: чтобы в приложении работали пуш-уведомления, устройство должно зарегистрироваться в пуш-платформе. Приложение вызывает метод notification-pushes, передаёт набор данных и в ответ получает «200 OK» — значит, зарегистрировались, и пуши будут приходить. На iPhone — «200 OK», всё прекрасно, получаем device-адрес, регистрируемся. На iPad — «400 Bad Request», ошибка «Provider UUID not found». Абсолютно одинаковая сборка. Одна и та же версия. Одинаковые настройки. Но на iPhone пуши работают, а на iPad — нет.
Я сначала думал, что дело — в хедерах: обычно устройство-специфичные проблемы бывают именно там. Но нет. Причину нашли в теле запроса — в JSON. Приложение при регистрации передавало атрибут OSName. iPhone отправлял значение iOS — бэкенд его принимал. iPad отправлял iPadOS — бэкенд не знал, что это такое, и возвращал ошибку. Одно строковое значение в JSON — и целая категория устройств остаётся без пуш-уведомлений. Пофиксили на бэке в лоб: если приходило iPadOS — сразу заменялось на iOS. И это повезло. Если вы никогда не фиксили пуши под Huawei, то многое пропустили в этой жизни.
Стандартные приколы
Вот тут никто не подумал, что этих тегов может быть много:

Что должно было происходить: при большом количестве чипсов внутри поля появляется скролл, и можно нормально прокручивать список. Что происходило на самом деле: скролл не появлялся.
С подобными UI-багами я сталкиваюсь довольно часто. Ничего экзотического, стандартная поехавшая вёрстка — но на живой форме, которой каждый день пользуются администраторы клиник: это означает реальную невозможность зарегистрировать врача с большим количеством специальностей.

А вот поехала типографика — буквы «р» в некоторых местах интерфейса рендерились с видимым смещением. Как бы не самый серьёзный баг, но есть люди, у которых это может вызвать психический срыв. И я сейчас не шучу.
Или вот финтех, чат с поддержкой. Бот-помощник пишет: «Здравствуйте, Ириней! Какой у вас вопрос?» Пользователь отвечает: «Вывод средств». Бот: «Выберите, какой счёт вас интересует». Ниже должна появиться чипса — по нажатию открывается шторка, «выборщик счетов». Пользователь выбирает конкретный счёт и получает информацию по нему.

Но если клиент откроет слишком много счетов, то кнопка внизу уедет навсегда. У неё фиксированное позиционирование, и при длинном списке счетов она просто не попадает в видимую область.
Или вот обмен сообщениями чата работает через WebSocket: устанавливается одно соединение, и в рамках этого соединения идёт вся коммуникация. Пишешь: «Привет!» — сообщение уходит через сокет. Чат-бот присылает набор чипсов с вариантами действий — нажимаешь на чипсу и получаешь нужную информацию. Когда заканчиваешь переписку и выходишь из чата, соединение закрывается с кодом «1000» — это стандартный код нормального завершения WebSocket. Так должно работать.
А тут при выходе из чата соединение не закрывалось. Код «1000» не отправлялся. Сокет просто оставался висеть. При повторном входе в чат открывалось новое соединение, а старое продолжало жить. И так — каждый раз.

Результат предсказуем: после нескольких входов-выходов из чата приложение крашилось.
Что случилось? Что угодно! Мой любимый детектив — когда переиспользуется библиотека основного банковского приложения. Логика понятная: зачем разрабатывать и поддерживать своё, если у старшего продукта всё уже есть? С одной стороны — удобно. С другой стороны — ты полностью зависишь от того, что делает соседняя команда, которая вообще может не думать о тебе.
Так что вот такие у нас тут увлекательные приключения. В целом это пока всё, что вам надо знать про работу тестировщика мобильных приложений!)
Комментарии (4)

aasokovykh
15.04.2026 09:35"Покрытие автотестами не очень высокое, потому что их тоже надо писать с AI"
Это насколько же неквалифицированные QA работают в вашей компании? Почему отсутствуют базовые смоук или е2е тесты из серии логин/логаут и отправить пару запросов?

xForeYx Автор
15.04.2026 09:35В статье не утверждается, что покрытия автотестами вообще нет. Оно есть, но не очень высокое. Его достаточно, чтобы покрыть критические сценарии, в том числе по UI и по API. В идеале нам хотелось бы покрыть подавляющую часть, чтобы не заниматься рутиной (теми самыми регрессами и смоуками), а заниматься продуктовым тестированием и работать над улучшением процессов.
computershik73
Как пофиксили на самсунгах и почему именно это происходило, так и не рассказали.
xForeYx Автор
RatingBar глубоко в иерархии основан на ProgressBar, а звезды там — скорее для красоты.
Когда пользователь нажимает на «звезду», под капотом происходит округление на основе параметра stepSize. И почему-то именно на Самсунгах оно часто срабатывает не в ту сторону, в которую хотелось бы.
То есть если нажать на самый край 4-й звезды, рейтинг выставлялся как 5, что со стороны выглядело как явный баг.
Решается так: устанавливаем stepSize = 0.01 и теперь самостоятельно в листенере округляем рейтинг до целого числа. Так всё работает корректно.