Gameplay- и integration-тестирование
Документация принадлежит движку. Руководство задает переиспользуемые правила выбора test boundary, детерминированных fixtures, process runner, markers, deadline, cleanup и evidence для игр на FOnline.
Назначение
Используйте этот маршрут, когда одного native unit test уже недостаточно, но проверка еще не требует packaged release или device lab. Движок поставляет project-neutral process runner и два уровня доказательства:
- Gameplay Test Harness проверяет сам runner без скомпилированной игры;
- Minimal Multiplayer проводит тот же runner через baked content, metadata, headless server/client, network, map load, remote calls, replicated state и interaction.
Native Catch2 targets, sanitizers и coverage описаны в Testing. Первый учебный end-to-end путь находится в First Automated Test.
Решение о тесте
Используйте boundary-based test selection и запускайте проверки narrow-first,
чтобы первый отказ давал focused failure location. Для process smoke объявляйте
ready_marker, упорядоченные required_markers, forbidden_markers и единый
deadline; всегда сохраняйте command lines, logs, причины завершения и результаты
cleanup. Engine владеет этим контрактом runner. Встраивающий проект владеет
своими script test registration API, каталогом fixtures, gameplay assertions,
acceptance thresholds, accounts, databases, scenes и release lanes.
Выберите минимальную владеющую границу
Выберите первый слой, который действительно наблюдает изменяемый контракт. Добавляйте более широкое доказательство только при пересечении новой границы.
| Граница изменения | Первое доказательство | Когда расширять |
|---|---|---|
| Native algorithm/data structure | focused Catch2 | construction, serialization, thread или runtime role меняют результат |
| Parser, baker, generated metadata | native test и bake | generated result потребляет runtime |
| Один script module/callback | project-owned side-specific script test | state пересекает module, entity, persistence или client/server |
| Prototype/map/text/resource | bake и semantic assertion | клиент обязан загрузить, показать, воспроизвести или дать взаимодействовать |
| Server lifecycle/world setup | один headless server | нужен network/client-observable результат |
| Protocol/gameplay interaction | ordered headless server/client smoke | заявлены presentation, package, device или backend |
| Package/updater/platform/release | package/platform acceptance | заявлены production infrastructure или recovery |
Это boundary-based selection, а не фиксированная пирамида. Broad smoke не заменяет focused failure location, а unit test не доказывает process/network/ baked-content границу, в которую не входит. Работайте narrow-first и останавливайтесь на первом сбое до расширения scope.
Контракт детерминированной fixture
- Используйте изолированные working directory, storage namespace, accounts, ports и outputs.
- Выберите checked-in named config/sub-config.
- Создайте только необходимые world/entities/authored references.
- Зафиксируйте управляемую случайность или удалите ее с test route.
- Печатайте low-volume semantic markers после readiness и asserted outcomes.
- После успеха запросите normal shutdown, проверяя teardown.
- Ограничьте каждый wait и сохраните process output плюс structured result.
Fixed sleep может только задавать pacing; pass condition обязан быть exit code, semantic marker, decoded artifact, state query или visible result владельца границы. Fixture очищает каждый созданный process/resource, использует уникальные ports либо serialized CI и никогда не обращается к production storage, credentials, accounts или services.
Контракт process runner
BuildTools/gameplay_test_runner.py выполняет checked JSON manifest без shell.
Command является массивом, а environment-specific values передаются как
{name} через повторяемый --value name=value.
Schema version 1 содержит:
- root:
name,default_timeout_seconds, optionalforbidden_markers, orderedscenarios; - scenario: stable
id, optional timeout/forbidden overrides, orderedprocesses; - process: stable
id, command array, optional working directory/environment, readiness, required/forbidden markers и expected exit code.
Unknown fields, duplicate ids/markers, неверные типы и unresolved placeholders являются configuration errors. Environment расширяет inherited process env. Secrets не помещаются в manifest, values, command, markers или report: command line и process environment могут наблюдаться извне.
{
"schema_version": 1,
"name": "project-smoke",
"default_timeout_seconds": 60,
"forbidden_markers": ["FATAL ERROR!", "ScriptException"],
"scenarios": [
{
"id": "server-client",
"processes": [
{
"id": "server",
"command": ["{server}", "-ApplyConfig", "{config}"],
"ready_marker": "project_server_ready",
"ready_timeout_seconds": 20,
"required_markers": ["project_server_ready", "project_server_passed"]
},
{
"id": "client",
"command": ["{client}", "-ApplyConfig", "{config}"],
"required_markers": ["project_client_connected", "project_client_passed"]
}
]
}
]
}
Из корня embedding project:
python Engine/BuildTools/gameplay_test_runner.py \
--manifest Tests/gameplay-smoke.json \
--value server=Build/bin/Game_ServerHeadless \
--value client=Build/bin/Game_ClientHeadless \
--value config=Game.fomain \
--report Workspace/gameplay-smoke-report.json
Пути и target names являются примерами; проект владеет generated executable names и layout.
Семантика readiness и markers
Processes запускаются по порядку manifest. При ready_marker следующий process
не стартует до marker или timeout; readiness budget ограничен общим scenario
deadline.
Runner объединяет stderr со stdout, декодирует UTF-8 с replacement, добавляет к строке suite/scenario/process identity и проверяет:
- каждый
required_markersпоявился в output этого process; - ни один process/scenario/suite
forbidden_markersне появился; expected_exit_code, по умолчанию 0, совпал точно.
Markers являются стабильными protocol tokens, а не prose. Печатайте их только после существования asserted state и не переносите в них шумные diagnostics. Marker доказывает достижение инструментированного состояния, но не ненаблюдавшиеся pixels, sound, durability, package contents или external service. Для них нужен владеющий decoder/query/screenshot/audible review/restart/ platform lane.
Deadlines и cleanup
Scenario имеет один monotonic deadline: readiness и completion расходуют общий budget. При сбое, timeout или incomplete startup runner идет по запущенным processes в обратном порядке, вызывает terminate, ждет до пяти секунд и затем kill-ит неостановившийся process.
Timeout является failure. Сначала выясните, не отсутствовал ли readiness, dependency, shutdown progress или deterministic timing. Повышайте limit только по измеренному valid work на supported CI hosts.
Контракт результата
0: все scenarios прошли;1: нарушен process/exit/marker/readiness/timeout contract;2: неверен CLI или manifest.
С --report записывается JSON schema version 1 со статусом и duration suite/
scenario, timeout, reasons, process exit codes и missing/forbidden markers.
Commands, environments и full logs намеренно исключены. CI сохраняет report и
prefixed process log вместе.
Интеграция с CMake и CI
Gameplay smoke оформляется named custom target с dependencies на точные binaries
и baked artifacts. Передавайте target paths через generator expressions,
держите manifest в SOURCES, используйте VERBATIM и terminal для interleaved
output. Исполняемый образец находится в
Minimal Multiplayer CMake.
Synthetic runner tests запускаются при каждом изменении runner/schema. Хотя бы один реальный headless server/client example нужен на каждой заявленной платформе. Product CI добавляет свои script tests, content assertions, packages, persistence backends, visible checks и release gates.
Маршрутизация ошибок
| Симптом | Сначала проверить |
|---|---|
| Exit 2 | schema, unknown fields, placeholders и KEY=VALUE |
| Process не стартовал | executable/cwd path и host permissions |
| Нет readiness marker | earliest log, config, startup dependencies, marker owner |
| Нет required marker | ближайший assertion, затем remote/entity/content state |
| Forbidden marker | первое появление и native/script source; реальную ошибку не allowlist-ить |
| Exit mismatch после markers | shutdown, teardown callbacks, worker/database drain |
| Timeout | последний marker каждого process, deadlock/dependency/cleanup |
| Локально green, CI red | ports, case, locale, capacity, graphics/audio assumptions, undeclared state |
Граница ответственности проекта
Движок не определяет script test registry игры, fixture catalog, gameplay assertions, accounts/databases, filters, authored ids, ports, timing budgets, package matrix, device lab или acceptance thresholds. Они остаются в проекте.
Project-specific orchestration является evidence, а не Engine API. Primitive продвигается в движок только с Engine-owned implementation, deterministic tests, independent guide и real public example.
AiControl/MCP adapter может дать semantic observations/actions внутри project smoke, но не заменяет deadline, cleanup, marker и report contracts runner-а. Endpoint schemas и gameplay tools остаются проектными; общий wire lifecycle описан в протоколе AiControl. Protocol-only Python sample не доказывает, что native FOnline client выполнил command или game server применил normal authority.
Проверенные исходные пути
BuildTools/gameplay_test_runner.pyBuildTools/tests/test_gameplay_test_runner.pyExamples/GameplayTestHarness/fixture_process.pyExamples/GameplayTestHarness/synthetic-smoke.jsonExamples/MinimalMultiplayer/tutorial-smoke.jsonExamples/MinimalMultiplayer/run_tutorial_smoke.pyExamples/MinimalMultiplayer/CMakeLists.txtExamples/MinimalMultiplayer/Scripts/Tutorial.fosSource/Applications/TestingApp.cppBuildTools/cmake/stages/Applications.cmake.github/workflows/validate.yml