
В медицинском программном обеспечении (ПО) за каждым назначением, статусом госпитализации, результатом анализа или записью в карте стоит не абстрактная сущность из тестовой базы, а человек. Врач принимает решение не по логам, а исходя из того, что видит на экране, и рассчитывает, что система показывает реальную картину. Система может вернуть 200 OK, сохранить запись и не показать ни одного сбоя, но медицинский процесс при этом не завершится: назначение останется в неверном случае лечения или лаборатория не получит заявку, или врач увидит старый статус. Такие дефекты не останавливают работу. Они позволяют продолжить её с неверными данными, и именно этим опасны.
Привет, Хабр!
Меня зовут Ольга Ришко, старший специалист по тестированию медицинской информационной системы (МИС) «БАРС Груп». В этой статье я расскажу, почему медицинское ПО нельзя проверять как набор отдельных экранов и API‑методов, откуда берутся «успешные» операции с неверным результатом, что именно ручной тестировщик ищет между интерфейсом, базой данных (БД), фоновыми задачами и интеграциями, где рождаются самые неприятные дефекты и почему ручное тестирование в медицинских технологиях по‑прежнему остается не запасным вариантом, а важной частью контроля качества.
Примеры ниже обезличены и собраны из типовых рабочих ситуаций. Важен не конкретный модуль или заказчик, а сам класс проблем: технически запрос выполнен, а пользовательская задача — нет.
Одна кнопка на экране, несколько процессов внутри
Возьмём простой сценарий. Врач назначает пациенту лабораторное исследование и нажимает «Сохранить». Для пользователя это одно действие. Внутри системы оно может раскладываться на целую цепочку:
проверить обязательные поля и права пользователя;
создать назначение и связать его с пациентом и текущим случаем лечения;
изменить статус связанного медицинского документа;
сформировать задание для лаборатории или процедурного кабинета;
отправить событие в интеграционную шину;
обновить списки и статусы на экране;
записать переход в историю изменений.
Часть шагов выполняется в одной транзакции, часть — отдельными сервисами, часть — уходит в очередь и завершается позже. У модулей могут быть разные владельцы данных, свои правила повторной обработки и собственные журналы. Добавим кэш, несколько открытых вкладок и внешнюю лабораторную систему — получим обычную для большой МИС архитектуру. Никакой мистики, просто много точек, где один результат должен согласовываться с другим.
Для меня, как для тестера, клинический сценарий — это не медицинский протокол лечения, а полный путь алгоритма работы в системе: кто и в каком случае лечения создал назначение, куда оно должно попасть, кто увидит его следующим, какой статус должен измениться и чем процесс должен закончиться. Если проверить только сохранение формы, большая часть этого пути останется за пределами теста.
Четыре способа получить «успешную» операцию с неверным результатом

1. Данные сохранились не в том контексте
У одного пациента одновременно могут существовать разные эпизоды лечения: амбулаторное обращение, госпитализация, дневной стационар. Внутри МИС назначение связано с карточкой пациента, конкретным случаем, подразделением, врачом и этапом оказания помощи. Это и есть контекст данных в прикладном смысле. Если интерфейс уже переключился на госпитализацию, а вложенный блок продолжил использовать идентификатор амбулаторного случая, запись создастся и будет валидной для базы. По итогу: есть факт формирования направления, получение результатов, запись в БД, запрос отдает двухсотку приятного цвета, логи в порядке. Только сотрудники стационара не увидят запись в своём рабочем списке. Потому что система считает, что пациент был в поликлинике на приеме, соответственно, она направит результаты анализов в поликлинический случай, а не в стационарный.
2. Основная запись обновилась, а связанные данные — нет
Такое происходит, когда одно пользовательское действие затрагивает несколько таблиц, модулей или сервисов. Например, врач отменяет исследование. Статус назначения меняется на «Отменено» и API честно возвращает успех. Но задание лаборатории обновляется отдельным обработчиком, который в этот момент завершился с ошибкой или не получил событие. В карточке пациента исследование отменено, а в лабораторном списке оно всё ещё ожидает выполнения. Обе подсистемы показывают данные из своих источников, поэтому каждая по отдельности выглядит логично.
3. Интерфейс показывает старое состояние
Запись в базе уже изменилась, но экран продолжает жить с ранее загруженными данными. Причиной может быть кэш, неотработавший обновление компонента или запрос, который завершился позже и перезаписал новое состояние старым ответом. Типичная боль — быстрое переключение между пациентами: шапка карточки уже относится к новому пациенту, а один из вложенных блоков на секунду или до следующего обновления показывает данные предыдущего.
4. Зависимая операция упала, но пользователь об этом не узнал
Основная часть сценария может завершиться синхронно, а передача данных во внешнюю систему — асинхронно. Документ сохранён, назначению присвоен номер, на экране появился зелёный статус. После этого фоновая задача пытается отправить сообщение в лабораторию и получает ошибку. Если результат фоновой обработки не возвращается в интерфейс, нет повторной отправки или отдельного статуса синхронизации, врач продолжает ждать исследование, о котором лаборатория ничего не знает.
Во всех четырёх случаях на одном из технических уровней всё действительно может быть исправно. Проблема появляется не «вопреки» успешной работе слоёв, а на их стыке: один слой уже считает операцию завершённой, а другой — ещё не получил изменение, обработал его иначе или остался в прежнем состоянии.
Что на самом деле означает 200 OK
HTTP‑статус 200 OK сообщает, что конкретный запрос был принят и обработан без явной ошибки на уровне протокола. Это полезный факт, но он не отвечает на более важные вопросы: завершились ли фоновые действия, обновились ли зависимые объекты, увидел ли результат следующий участник процесса и соответствует ли итог бизнес‑правилам.
Поэтому в тестировании МИС я воспринимаю 200 OK как промежуточную точку. После него начинается проверка результата: что записалось, с какими связями, какой статус увидят другие роли и можно ли продолжить сценарий до ожидаемого конца.
Иногда API дополнительно возвращает бизнес‑статус или идентификаторы созданных объектов. Это помогает, но не отменяет сквозную проверку. Сервер может корректно сообщить: «Назначение создано». Из этого ещё не следует: «Лаборатория получила задание и готова его выполнить».
Ручка начинается не с формы
Тема, о которую до сих пор ломаются копья. Наверное, глобальнее только вопрос окрошки. Я не противопоставляю ручное тестирование автоматизации. В реальной работе — автоматизация и ручное тестирование решают разные задачи. Автотесты отлично держат регресс, быстро проверяют повторяющиеся сценарии и помогают убедиться, что после изменений система не посыпалась по верхнему контуру.
Но сначала кто‑то должен понять, какой именно результат считается корректным и где у процесса слабые места. Перед проверкой я раскладываю сценарий не по экранам, а по участникам и последствиям. Кто выполняет действие? В каком случае лечения? Какие сущности должны измениться? Кто увидит результат следующим? Есть ли этап, который завершится не сразу? Что останется на экране, если этот этап упадёт?
Например, для того же лабораторного назначения мало убедиться, что форма сохранилась. Нужно проверить, появилось ли исследование в нужном эпизоде, изменился ли статус документа, сформировалось ли задание, видит ли его лаборатория, не продублировалась ли заявка после повторного нажатия и что произойдёт при отмене. Это проверка смысла операции.
Пользователь не идёт по идеальному пути
Автотест обычно дисциплинирован: дождался ответа, выполнил следующий шаг, закрыл сценарий. Живой человек так не работает. Именно поэтому в исследовательском тестировании я специально ухожу с ровной дорожки. Не манки‑тестом, конечно, но проверяю гипотезы о риске. Например:
• что произойдёт при двойном сохранении;
• какой ответ победит, если два запроса завершатся в другом порядке;
• увидит ли второй пользователь изменения без перезагрузки;
• останутся ли данные корректными после переключения между пациентами;
• можно ли повторить операцию после частичного зависания;
• как выглядит состояние, когда основная запись уже создана, а фоновая обработка ещё идёт.
Такие проверки особенно полезны на границах модулей. Внутри одного экрана разработчик обычно хорошо контролирует состояние. На переходе к очереди, внешнему сервису или другому рабочему месту появляется больше допущений: событие точно придёт, пользователь не нажмёт повторно, старый ответ не «перетрёт» новый, связанная запись обязательно найдётся. Баги любят уверенные гипотезы=)
Как я ищу место, где сценарий разошёлся
Прохожу путь, который прошли данные. Например, после отмены исследования врач видит статус «Отменено», а лаборатория продолжает видеть активное задание. Я проверяю это по шагам:
1. повторяю сценарий на интерфейсе и фиксирую момент расхождения;
2. в DevTools смотрю запрос отмены, полезную нагрузку, ответ и последующие обращения экрана;
3. при необходимости повторяю запрос через Postman, чтобы отделить поведение API от состояния интерфейса;
4. в БД сверяю статус назначения, связь с заданием и время изменений;
5. в логах и/или журнале историй запросов ищу событие отмены и результат его обработки;
6. проверяю рабочее место лаборатории и понимаю, какое состояние дошло до следующего участника процесса.
Предположим, основная запись в базе данных действительно получила статус «Отменено», но сообщения об отмене в журнале нет. Тогда проблема уже не выглядит как абстрактное «в разных местах — разные статусы». Появляется конкретная граница: транзакция назначения завершилась, а событие для связанного модуля не сформировалось. В отчете об ошибках можно указать не только видимый результат, но и вероятный участок сбоя, затронутые роли и риск повторного выполнения исследования. Чем точнее локализовано расхождение, тем быстрее команда поймёт, что исправлять и какие соседние сценарии проверить.
Чек‑лист нужен. Но он не умеет задавать вопросы
Чек‑листы, тест‑кейсы, дымовое и регрессионное тестирование остаются основой работы. Без них через несколько релизов команда начинает проверять систему по памяти. Но формальный сценарий чаще всего описывает ожидаемый путь: открыть, заполнить, сохранить, проверить статус. Риск возникает между этими шагами или после них. Поэтому к готовому тест‑кейсу я добавляю вопросы, которых может и не быть в требованиях:
• что считается завершением операции для пользователя, а не только для API;
• как система обозначает частично выполненный процесс;
• какие данные увидит другая роль;
• что произойдёт при задержке или недоступности зависимости;
• не подменяет ли интерфейс неопределённое состояние словом «успешно».
Для медицинского ПО это не придирки к UX. Это опять же про надежность процесса.
Что изменил мой опыт работы с МИС
Работа с медицинской системой очень быстро развивает тревожность и орлиные глаза. Когда все хорошо, это подозрительно. Со временем начинаешь смотреть не на отдельную функцию, а на цепочку состояний: что было до действия, что должно измениться после него и кто зависит от результата.
Я вынесла из этой работы три практических правила.
1. Ни интерфейс, ни API, ни запись в базе сами по себе не доказывают, что сценарий завершён корректно.
2. Чем тише дефект, тем важнее проверить последствия. Явная ошибка останавливает пользователя, скрытая позволяет ему идти дальше.
3. Ручное тестирование особенно ценно там, где нужно сопоставить технический результат с реальным действием врача, регистратора, лаборатории или другого участника процесса.
Качество медицинской системы живёт на стыке интерфейса, данных, фоновых процессов, интеграций и человеческого решения. Поэтому 200 OK для меня не финал проверки. Это всего лишь подтверждение, что один шаг не упал.
