Summary
Полный аудит тестовой suites (1823 теста, 68 тест-классов, 28 файлов) выявил 20 проблем. Все 12 предполагаемых багов в коде direct_cli/ были опровергнуты при валидации на текущей кодовой базе — код корректен.
High (2)
1. test_integration.py:180,203,254,455,478,509,532 — setUpClass вызывает API без try/except
7 тест-классов (TestReadOnlyAdGroups, TestReadOnlyAds, TestReadOnlyKeywords, TestReadOnlyDynamicFeedAdTargets, TestReadOnlyLeads, TestReadOnlyBusinesses, TestReadOnlyAdVideos) имеют setUpClass, вызывающий invoke_get() или probe-функции. Если API недоступен, setUpClass выбросит исключение, которое не превращается в skip — unittest.TestCase.setUpClass не умеет в pytest.skip().
Сценарий: При временной недоступности API весь тест-класс падает с traceback вместо graceful skip.
2. test_integration.py:45-48 — setUpClass работает до skip_if_no_token
invoke_get() вызывает CLI через CliRunner().invoke(cli, list(args)) без передачи env-переменных с токеном. Тесты зависят от того, что load_dotenv() сработал при import. Если dotenv не загрузился или токен отсутствует, все интеграционные тесты fail с непонятной ошибкой, а не skip. Декоратор skip_if_no_token стоит на классе, но setUpClass вызывается раньше отдельных тестов.
Сценарий: CI runner без .env файла и без env vars: setUpClass вызывает API без токена → непонятная ошибка вместо skip.
Medium (7)
3. test_comprehensive.py — Дублирование с test_cli.py
Файл практически полностью дублирует test_cli.py. TestCLIHelp, TestCommandsRegistered, TestUtils, TestOutputFormatters, TestAuth, TestErrorHandling — те же классы/тесты. test_cli_help, test_missing_token_raises, test_token_from_argument и др. — точные дубли.
Сценарий: Изменение логики в одном месте без синхронизации другого создаёт расхождение.
4. test_integration.py:73-79 — get_first_campaign_id() вызывается многократно без кэширования
Делает живой API-запрос при каждом вызове. Вызывается в 7 разных setUpClass и ещё раз inline. Если между вызовами данные изменяются или API throttled, разные тест-классы получат разный campaign_id или None.
Сценарий: При parallel execution или rate limiting разные классы получат разные результаты.
5. test_smoke_matrix.py:62-64 — Хардкод количества subcommands
assert summary["total_cli_subcommands"] == 144 и assert summary["wsdl_operations"] == 112. При добавлении/удалении команды или WSDL-операции тест падает с непонятным сообщением.
Сценарий: Добавление нового WSDL-метода или CLI-команды ломает тест.
6. test_sandbox_write_audit.py:35 — Хардкод числа команд
assert audit["summary"]["total"] == 83. При добавлении новой команды тест упадёт пока число не обновят.
7. conftest.py:369-433 — Sandbox fixtures создают цепочку зависимостей
sandbox_keyword → sandbox_adgroup → sandbox_campaign. Если sandbox_ad fixture падает mid-way, _safe_delete в teardown вызывает delete для уже удалённого ресурса, генерируя misleading error logs.
8. test_v5_live_write.py — Interrupted run оставляет ресурсы без cleanup
Live-write тесты создают реальные ресурсы. При interrupt cleanup не гарантируется. _orphan_store.py частично решает проблему, но только для v4-report ресурсов.
9. test_integration.py:46-48 — invoke_get не передаёт credentials явно
Токен берётся из окружения через load_dotenv(). Если env-переменные очищены в CI runner, интеграционные тесты не работают.
Low (11)
10. conftest.py:56 — Module-level credential resolution при import
_REAL_TOKEN, _REAL_LOGIN = _resolve_test_credentials() выполняется на module import. При pytest --collect-only запускается credential resolution, хотя тесты не выполняются.
11. test_dry_run.py — 989 тестов, 21718 строк (622KB)
Diff review практически невозможен.
12. test_low_coverage_payloads.py:30-31 — Mock через patch строки
Патчит direct_cli.cli.get_active_profile вместо настройки CliRunner env. Может пропустить regression если auth-chain изменится.
13. test_v4_live_contracts.py — _credentials() вызывается внутри каждого теста
N+1 credential resolution вместо fixture.
14. test_comprehensive.py:36-77 — EXPECTED_COMMANDS не синхронизирован с test_cli.py
Список может рассинхронизироваться при добавлении нового ресурса.
15. test_auth_oauth.py — 1606 строк, 53KB
Объём затрудняет review.
16. conftest.py:198-202 — _invoke() не передаёт _REAL_LOGIN при replay
VCR matching по body может не совпасть при переключении match_on.
17. test_wsdl_parity_gate.py — 5660 строк, 14 тестов, огромные data-структуры
Изменение WSDL требует обновления 3-4 разных структур.
18. test_integration.py:686-694 — Auth status edge case
Если формат auth status изменится, skipTest может не сработать.
19. tests/ — Нет тестов на конкурентные сценарии
Параллельный запуск с xdist может конфликтовать при записи в test-orphans.json.
20. test_changes.py — Только integration-тесты
Нет unit-тестов для changes check с конкретными fieldnames комбинациями.
Код-аудит: все баги опровергнуты
Все 12 потенциальных багов в direct_cli/ (reports.py KeyError, campaigns.py TypeError, adgroups.py copy-paste, ads.py TextAd-only update, keywords.py hardcoded bid, bidmodifiers.py unknown types) были перепроверены на текущем коде и оказались ложными — предыдущий агент анализировал усечённые файлы (Read tool обрезал ~7500-строчные файлы до 200-500 строк).
🤖 Generated with Claude Code
Summary
Полный аудит тестовой suites (1823 теста, 68 тест-классов, 28 файлов) выявил 20 проблем. Все 12 предполагаемых багов в коде
direct_cli/были опровергнуты при валидации на текущей кодовой базе — код корректен.High (2)
1.
test_integration.py:180,203,254,455,478,509,532— setUpClass вызывает API без try/except7 тест-классов (
TestReadOnlyAdGroups,TestReadOnlyAds,TestReadOnlyKeywords,TestReadOnlyDynamicFeedAdTargets,TestReadOnlyLeads,TestReadOnlyBusinesses,TestReadOnlyAdVideos) имеютsetUpClass, вызывающийinvoke_get()или probe-функции. Если API недоступен,setUpClassвыбросит исключение, которое не превращается в skip —unittest.TestCase.setUpClassне умеет вpytest.skip().Сценарий: При временной недоступности API весь тест-класс падает с traceback вместо graceful skip.
2.
test_integration.py:45-48— setUpClass работает до skip_if_no_tokeninvoke_get()вызывает CLI черезCliRunner().invoke(cli, list(args))без передачи env-переменных с токеном. Тесты зависят от того, чтоload_dotenv()сработал при import. Если dotenv не загрузился или токен отсутствует, все интеграционные тесты fail с непонятной ошибкой, а не skip. Декораторskip_if_no_tokenстоит на классе, ноsetUpClassвызывается раньше отдельных тестов.Сценарий: CI runner без
.envфайла и без env vars:setUpClassвызывает API без токена → непонятная ошибка вместо skip.Medium (7)
3.
test_comprehensive.py— Дублирование сtest_cli.pyФайл практически полностью дублирует
test_cli.py.TestCLIHelp,TestCommandsRegistered,TestUtils,TestOutputFormatters,TestAuth,TestErrorHandling— те же классы/тесты.test_cli_help,test_missing_token_raises,test_token_from_argumentи др. — точные дубли.Сценарий: Изменение логики в одном месте без синхронизации другого создаёт расхождение.
4.
test_integration.py:73-79—get_first_campaign_id()вызывается многократно без кэшированияДелает живой API-запрос при каждом вызове. Вызывается в 7 разных
setUpClassи ещё раз inline. Если между вызовами данные изменяются или API throttled, разные тест-классы получат разныйcampaign_idилиNone.Сценарий: При parallel execution или rate limiting разные классы получат разные результаты.
5.
test_smoke_matrix.py:62-64— Хардкод количества subcommandsassert summary["total_cli_subcommands"] == 144иassert summary["wsdl_operations"] == 112. При добавлении/удалении команды или WSDL-операции тест падает с непонятным сообщением.Сценарий: Добавление нового WSDL-метода или CLI-команды ломает тест.
6.
test_sandbox_write_audit.py:35— Хардкод числа командassert audit["summary"]["total"] == 83. При добавлении новой команды тест упадёт пока число не обновят.7.
conftest.py:369-433— Sandbox fixtures создают цепочку зависимостейsandbox_keyword→sandbox_adgroup→sandbox_campaign. Еслиsandbox_adfixture падает mid-way,_safe_deleteв teardown вызывает delete для уже удалённого ресурса, генерируя misleading error logs.8.
test_v5_live_write.py— Interrupted run оставляет ресурсы без cleanupLive-write тесты создают реальные ресурсы. При interrupt cleanup не гарантируется.
_orphan_store.pyчастично решает проблему, но только для v4-report ресурсов.9.
test_integration.py:46-48—invoke_getне передаёт credentials явноТокен берётся из окружения через
load_dotenv(). Если env-переменные очищены в CI runner, интеграционные тесты не работают.Low (11)
10.
conftest.py:56— Module-level credential resolution при import_REAL_TOKEN, _REAL_LOGIN = _resolve_test_credentials()выполняется на module import. Приpytest --collect-onlyзапускается credential resolution, хотя тесты не выполняются.11.
test_dry_run.py— 989 тестов, 21718 строк (622KB)Diff review практически невозможен.
12.
test_low_coverage_payloads.py:30-31— Mock через patch строкиПатчит
direct_cli.cli.get_active_profileвместо настройки CliRunner env. Может пропустить regression если auth-chain изменится.13.
test_v4_live_contracts.py—_credentials()вызывается внутри каждого тестаN+1 credential resolution вместо fixture.
14.
test_comprehensive.py:36-77—EXPECTED_COMMANDSне синхронизирован сtest_cli.pyСписок может рассинхронизироваться при добавлении нового ресурса.
15.
test_auth_oauth.py— 1606 строк, 53KBОбъём затрудняет review.
16.
conftest.py:198-202—_invoke()не передаёт_REAL_LOGINпри replayVCR matching по body может не совпасть при переключении match_on.
17.
test_wsdl_parity_gate.py— 5660 строк, 14 тестов, огромные data-структурыИзменение WSDL требует обновления 3-4 разных структур.
18.
test_integration.py:686-694— Auth status edge caseЕсли формат auth status изменится,
skipTestможет не сработать.19.
tests/— Нет тестов на конкурентные сценарииПараллельный запуск с xdist может конфликтовать при записи в
test-orphans.json.20.
test_changes.py— Только integration-тестыНет unit-тестов для
changes checkс конкретными fieldnames комбинациями.Код-аудит: все баги опровергнуты
Все 12 потенциальных багов в
direct_cli/(reports.py KeyError, campaigns.py TypeError, adgroups.py copy-paste, ads.py TextAd-only update, keywords.py hardcoded bid, bidmodifiers.py unknown types) были перепроверены на текущем коде и оказались ложными — предыдущий агент анализировал усечённые файлы (Read tool обрезал ~7500-строчные файлы до 200-500 строк).🤖 Generated with Claude Code