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

А вы знали, что ручные тесты могут быть кодом?
Если вы считаете, что ручные тест-кейсы нужны исключительно для таблиц и интерфейсов, у нас есть новости: их можно хранить в Git как код. И не просто хранить, а интегрировать с ТестОпс. Почему это удобно? Потому что это делает управление тестами более эффективным, а данные — безопасными и надёжными.
Почему мы решили хранить ручные тесты в Git?
Однажды наш сервер, где был развернут ТестОпс, дал сбой, и часть данных пропала. Это побудило нас к поиску надежного способа их хранения. Автотесты мы восстановили, условно, за пару дней, а вот с ручными тестами всё было намного хуже: на их восстановление ушли месяцы работы нескольких человек.
Это стало уроком. Мы задумались: если автотесты отлично чувствуют себя в Git, то почему бы не хранить там и ручные тест-кейсы? Проконсультировавшись с нашими коллегами из ТестОпс, мы поняли, что используя Git мы не только обезопасим данные, но и получим целый набор бонусов:
Стабильность: никакой потерянной работы.
Контроль: каждая правка на виду.
Удобство массового рефакторинга: нужно поменять общий шаг? Пара строк в коде — и готово.
И самое главное: Git учит людей расти профессионально. Многим тестировщикам, проводящим ручные проверки, интересно двигаться в сторону автоматизации. Работа с Git и IDE — это отличный способ подтянуть навыки и понять азы кодинга. А ведь в будущем такие знания могут стать билетом в мир автоматизации!
Как мы перенесли тесты из ТестОпс в Git?
Встает вопрос: как забрать всё накопленное в ТестОпс и аккуратно сложить в Git? Ответ прост: мы написали свой скрипт для выгрузки. Честно говоря, без него это было бы похоже на попытку собрать пазл без картинки на коробке.
Итак, что сделал наш скрипт?
1. Подключение к API ТестОпс
Мы заранее знали, какие наборы тестов (suites) хотим перенести. Через API скрипт запрашивал информацию и поэтапно проходился по всем тестам. В процессе пришлось учитывать правила RQL (Request Query Language), который задаёт формат и синтаксис для работы с данными. Этот подход позволил чётко структурировать запросы, обеспечив точность и полноту извлекаемой информации:
def get_all_suite_allure_ids(suite: str) -> list:
"""Получить все id указанного Suite."""
ids = []
page = 0
params = {
"projectId": project_id,
"rql": f'cf["Suite"] = "{suite}"',
"deleted": False,
"page": str(page),
"size": "20"
}
response: Response = requests.get(
"https://omp.allure.pro/api/rs/testcase/__search",
params=params,
headers=headers,
json=json_data
)
totalPages = response.json()["totalPages"]
print(f"Найдено страниц: {totalPages}")
while page < totalPages:
params["page"] = str(page)
response: Response = requests.get(
"https://omp.allure.pro/api/rs/testcase/__search",
params=params,
headers=headers,
json=json_data
)
cases_list = response.json()['content']
for case in cases_list:
if "id" in case:
id = case["id"]
ids.append(id)
page += 1
print(f"Found: {len(ids)}")
return ids
2. Сохранение в файлы
Внутри этого файла тесты превращались в понятный, поддерживаемый код. Мы сохраняли все метки (labels), слои (layers) и имена тестов:
@allure.id('23290')
@allure.title('Сообщения сортируется по дате')
def test_23290():
"""
Предварительное условие:
1. Пользователь успешно аутентифицирован системой (выполнен UC Аутентификация
пользователя в EMM или AppStore);
2. Устройство создано в системе и находится в группе устройств, в группе есть политика,
назначаем правило.
"""
with allure.step('[Phone] Нажать "Получить обновления" в клиенте "Аврора Центр"'):
with allure.step('Обновления получены'):
pass
with allure.step('[EMM] Добавить любое правило в политику'):
with allure.step('Правило добавлено'):
pass
with allure.step(
'[Phone] Повторно нажать "Получить обновления" в клиенте "Аврора Центр"'
):
with allure.step('Обновления получены'):
pass
with allure.step('[Phone] Обратить внимание на сортировку сообщений'):
with allure.step('Сообщения сортируются по дате/времени'):
pass
Примечание: не стоит удивляться отсутствию отступов в документации функции.
Такое решение было принято намеренно, о чём можно прочитать далее в разделе “Сложности? Конечно, без них никуда”.
3. Чистота и порядок
Мы настроили логику так, чтобы скрипт автоматически устранял дубли и корректно обрабатывал сложные сценарии. А если попадалась какая-то экзотика, например, нестандартный формат шага, он просто сигнализировал.
4. Унификация
Когда скрипт закончил работу, все тесты в Git стали выглядеть единообразно: структура, формат, соглашения. Теперь они выглядят так, будто всегда хранились в коде, а не в интерфейсе ТестОпс:
@allure.id('23290')
@allure.title('Сообщения сортируется по дате')
def test_23290():
"""
Предварительное условие:
1. Пользователь успешно аутентифицирован системой (выполнен UC Аутентификация
пользователя в EMM или AppStore);
2. Устройство создано в системе и находится в группе устройств, в группе есть политика,
назначаем правило.
"""
with allure.step('[Phone] Нажать "Получить обновления" в клиенте "Аврора Центр"'):
with allure.step('Обновления получены'):
pass
with allure.step('[EMM] Добавить любое правило в политику'):
with allure.step('Правило добавлено'):
pass
with allure.step(
'[Phone] Повторно нажать "Получить обновления" в клиенте "Аврора Центр"'
):
with allure.step('Обновления получены'):
pass
with allure.step('[Phone] Обратить внимание на сортировку сообщений'):
with allure.step('Сообщения сортируются по дате/времени'):
pass
```
Сложности? Конечно, без них никуда
Если вы думаете, что всё прошло гладко, спешим развеять иллюзии. Были нюансы. Вот самые яркие:
1. "Автотест" по умолчанию
Оказывается, ТестОпс считает, что всё, загружаемое через Git, — автоматизированное. Чтобы обозначить, что тест-кейс ручной, пришлось искать, как это "сказать" в коде. Достаточно просто указать метку:
allure.label('ALLURE\_MANUAL', 'true')
2. Документация и Python: битва за форматирование
Python рекомендует форматировать отступы в документации. Казалось бы, что может пойти не так? Но ТестОпс воспринимает такие отступы как цитаты. В итоге пришлось нарушать правила Python, чтобы описания выглядели нормально. Немного боли для перфекциониста, но пришлось смириться, ради великой цели, что поделаешь:
@allure.id('23290')
@allure.title('Сообщения сортируется по дате')
def test_23290():
"""
Предварительное условие:
1. Пользователь успешно аутентифицирован системой (выполнен UC Аутентификация
пользователя в EMM или AppStore);
2. Устройство создано в системе и находится в группе устройств, в группе есть политика,
назначаем правило.
"""
3. Неудобство обновления ручных тестов
У нас расписание: запуски закрываются через неделю, так удобнее для регресса. Пришлось автоматизировать процесс: добавили в pipeline шаг с закрытием запусков через api принудительно:

Ревью: новая жизнь ручных тестов
Вы когда-нибудь видели плохо написанный ручной тест-кейс? Уверен, что да. Но как часто их отправляют на ревью? Скорее всего, редко.
Автоматизированные тесты, напротив, почти всегда проходят ревью. Мы решили, что ручные тесты заслуживают такого же внимания.
Теперь каждый ручной тест-кейс проходит цикл проверки:
Тест-кейс отправляется на ревью.
Коллеги анализируют его, дают обратную связь и предлагают улучшения.
Только после одобрения тест попадает в мастер.
Этот подход помогает повысить качество тестов. В результате мы уверены, что каждый тест понятен и не вызовет вопросов при прохождении.
Git: новые возможности для ручных тестов
Хранение ручных тестов в Git принесло несколько важных преимуществ:
-
История изменений.
Вы всегда можете увидеть, кто и что менял. Это особенно важно для крупных проектов, где над тестами работает большая команда.
-
Масштабируемость.
Изменить шаг во всех кейсах? Добавить новую функциональность? Всё это легко сделать через код.
-
Надёжность.
Даже если с ТестОпс что-то случится, все данные останутся в Git.
-
Коллаборация.
Git позволяет обсуждать спорные моменты, вносить коллективные изменения и улучшать тесты.
-
Интеграция и единство.
Мы не проводим четкой границы между “ручниками” и “автоматизаторами”. Для нас важно, чтобы каждый мог развиваться в обеих областях. Ручные тестировщики получают возможность погружения в автоматизацию и развитие своих навыков (в данном случае использование Git и IDE), а автоматизаторы — шанс стать более гибкими и креативными, участвуя в тест-дизайне и ручном тестировании. Этот подход позволяет нам создавать сильную команду, где каждый чувствует себя важным звеном.
Стоит ли игра свеч?
Конечно, не всё так идеально. Некоторые вещи пришлось делать через костыли. Но результат стоит того. Мы объединили удобство работы с кодом и гибкость ТестОпс, получив инструмент, который работает на нас, а не наоборот.
Если вы тоже думаете о подобной интеграции, помните: тесты как код — это не просто тренд. Это способ делать свою работу быстрее и надёжнее.
GlenTwan
кажется ссылка не работает
omprussia Автор
Спасибо. Похоже, придется без неё.