Где автотесты сдаются: живой стенд для голосовой комнаты
Проверка голосовой комнаты вдвоём дала четыре симптома: три свелись к одной гонке на 250 мс, четвёртый остался без объяснения. Разбираю, что из этого ловится автотестом за секунду и что требует живых людей с наушниками.
Голосовая комната в моём форке Buzz — это канал типа voice, который живёт постоянно, как в Discord. Зашёл утром, сидишь фоном, видишь, кто уже сидит. Ветка отдельная, upstream не трогаю. Автоматических проверок в проекте пока ноль: единственный гейт — npm run check, а он смотрит только типы.
Что дала проверка живыми людьми
19 августа мы зашли в комнату вдвоём. Вылезли четыре штуки:
- я не слышал собеседника;
- «меня выбило», когда второй зашёл;
- выйти и зайти помогло;
- слышно плохо.
Логи реле свели первые три к одной причине. Комната раскалывалась: внутри одного голосового канала жили два независимых созвона, интерфейс перескакивал на чужой. Корень — признаком «реле дошлёт историю присутствия» служил таймаут в 250 мс. Клиент ждал четверть секунды, ничего не получал и делал вывод, что он в комнате первый. Второй клиент приходил к тому же выводу. Дальше два «первых» строили каждый свою комнату.
Повторный вход помогал по банальной причине: к моменту второй попытки история уже была получена.
Четвёртый симптом — «слышно плохо» — остался без объяснения. Это отдельная история, и именно она задаёт границу темы.
Где автотест сильнее человека
Гонка на 250 мс — идеальная мишень. Тест поднимает реле, подключает двух фейковых клиентов в один канал, даёт им подключиться и утверждает: идентификатор созвона у обоих совпал. Такой тест отрабатывает за секунду и говорит одну фразу вместо четырёх пользовательских формулировок.
Второй плюс — воспроизводимость редкого. Гонка вылезает при определённом порядке событий. Человек зайдёт десять раз удачно и решит, что всё починено. Тест с подменённым таймером ставит эксперимент ровно в ту точку, где ломается.
Что ещё берут автотесты без вопросов:
- состояние присутствия: кто в комнате, кто вышел, кто отвалился по таймауту;
- порядок сообщений сигналинга и реакция на их отсутствие;
- таймауты и ретраи, если время в коде управляемое;
- права: пускает ли комната того, кого пускать нельзя;
- сериализация — то, что глазами вообще не увидишь, пока не сломается у пользователя.
Раннер я беру встроенный, node:test. Новых зависимостей ради этого добавлять не буду.
Где автотест бессилен
«Слышно плохо». Тут ломается сама идея проверки утверждением. Автотест сравнивает значения. Качество звука — это восприятие. Можно померить jitter, потери пакетов и битрейт, получить зелёные цифры и при этом с трудом разбирать собеседника.
Вещи, которые дают именно такую картину:
- эхо от колонок, когда наушники сняли;
- автоусиление, подрезающее начало фраз;
- шумодав, съедающий согласные;
- реальные микрофоны и драйверы, у каждого свои;
- разрешения браузера, которые пользователь выдал наполовину;
- NAT и TURN — трафик пошёл в обход, задержка выросла;
- вкладка в фоне и уснувший ноутбук.
Сюда же — ощущение «выбило». В логах это может выглядеть как штатный переход между созвонами. Что это ломает сценарий, скажет только человек.
Как я делю
Правило вышло короткое. Симптом сводится к состоянию — это автотест. Симптом сводится к ощущению или к железу — это стенд. Гонка на 250 мс сводится к состоянию: два клиента, один канал, один созвон. Проверяется без человека.
Полезный побочный эффект: разбор с логами реле переводит расплывчатые жалобы в проверяемые утверждения. Три жалобы стали одним утверждением, и на него уже пишется тест. Оставшаяся жалоба про звук осталась жалобой — значит, её место в чек-листе стенда.
Стенд — это дешевле, чем звучит
Никакой инфраструктуры я под это не поднимаю. Стенд — два окна на разных машинах, наушники, чек-лист и включённая запись логов реле. Пунктов десяток: зайти первым, зайти вторым, зайти третьим, свернуть вкладку, отключить микрофон, уронить сеть, вернуться. После каждого прохода — короткая запись, что услышал и что показал список участников.
Смысл стенда в том, что он ловит новые формулировки проблем. Автотест ловит уже известные. Каждый раз, когда стенд выдаёт симптом, который сводится к состоянию, он переезжает в node:test и больше человека не отвлекает.
Что дальше
Первый тест — тот самый: два клиента, один канал, совпавший созвон. Второй — на историю: пришедший вторым получает список присутствующих без опоры на таймер. Третий — на список участников в боковой панели, там сейчас число вместо ников, и ломаться оно будет тихо.
Баг #4 нашли люди. Нашли за час и четырьмя разными словами. Тест нашёл бы за секунду и одним.
Исследовательская сессия автоматизации
Очно или в Zoom разбираю вашу работу изнутри, ставлю гипотезы и тут же применяю их на реальной задаче. Уходите с инструментом, который уже работает.