[{"data":1,"prerenderedAt":756},["ShallowReactive",2],{"navigation":3,"doc-/backend/testing":217,"docs-all-paths":701},[4,19,39,63,87,111,127,195,211],{"title":5,"path":6,"stem":7,"children":8},"Welcome","/welcome","01.welcome",[9,11,15],{"title":5,"path":6,"stem":10},"01.welcome/index",{"title":12,"path":13,"stem":14},"Astar とは（5分）","/welcome/product-in-5-min","01.welcome/01.product-in-5-min",{"title":16,"path":17,"stem":18},"事業文脈","/welcome/business-context","01.welcome/02.business-context",{"title":20,"path":21,"stem":22,"children":23},"Getting Started","/getting-started","02.getting-started",[24,27,31,35],{"title":25,"path":21,"stem":26},"はじめかた","02.getting-started/index",{"title":28,"path":29,"stem":30},"リポジトリ取得と環境構築","/getting-started/repo-setup","02.getting-started/01.repo-setup",{"title":32,"path":33,"stem":34},"日々の開発ループ","/getting-started/dev-loop","02.getting-started/02.dev-loop",{"title":36,"path":37,"stem":38},"検証の 4 層","/getting-started/verification-tiers","02.getting-started/03.verification-tiers",{"title":40,"path":41,"stem":42,"children":43},"Architecture","/architecture","03.architecture",[44,47,51,55,59],{"title":45,"path":41,"stem":46},"アーキテクチャ","03.architecture/index",{"title":48,"path":49,"stem":50},"マルチテナンシーと RLS","/architecture/multi-tenancy-rls","03.architecture/01.multi-tenancy-rls",{"title":52,"path":53,"stem":54},"認可モデル","/architecture/authorization","03.architecture/02.authorization",{"title":56,"path":57,"stem":58},"AI サブシステム","/architecture/ai-subsystem","03.architecture/03.ai-subsystem",{"title":60,"path":61,"stem":62},"データモデル","/architecture/data-model","03.architecture/04.data-model",{"title":64,"path":65,"stem":66,"children":67},"Backend","/backend","04.backend",[68,71,75,79,83],{"title":69,"path":65,"stem":70},"バックエンド","04.backend/index",{"title":72,"path":73,"stem":74},"層構造","/backend/layering","04.backend/01.layering",{"title":76,"path":77,"stem":78},"規約","/backend/conventions","04.backend/02.conventions",{"title":80,"path":81,"stem":82},"テスト","/backend/testing","04.backend/03.testing",{"title":84,"path":85,"stem":86},"マイグレーション","/backend/migrations","04.backend/04.migrations",{"title":88,"path":89,"stem":90,"children":91},"Frontend","/frontend","05.frontend",[92,95,99,103,107],{"title":93,"path":89,"stem":94},"フロントエンド","05.frontend/index",{"title":96,"path":97,"stem":98},"モジュール内部構造","/frontend/module-anatomy","05.frontend/01.module-anatomy",{"title":100,"path":101,"stem":102},"API アクセスの一本道","/frontend/api-access-chain","05.frontend/02.api-access-chain",{"title":104,"path":105,"stem":106},"i18n","/frontend/i18n","05.frontend/03.i18n",{"title":108,"path":109,"stem":110},"デザインシステム","/frontend/design-system","05.frontend/04.design-system",{"title":112,"path":113,"stem":114,"children":115},"Go Agent And Cli","/go-agent-and-cli","06.go-agent-and-cli",[116,119,123],{"title":117,"path":113,"stem":118},"Go agent と CLI","06.go-agent-and-cli/index",{"title":120,"path":121,"stem":122},"Go agent","/go-agent-and-cli/go-agent","06.go-agent-and-cli/01.go-agent",{"title":124,"path":125,"stem":126},"CLI","/go-agent-and-cli/cli","06.go-agent-and-cli/02.cli",{"title":128,"path":129,"stem":130,"children":131},"Modules","/modules","07.modules",[132,135,139,143,147,151,155,159,163,167,171,175,179,183,187,191],{"title":133,"path":129,"stem":134},"モジュール","07.modules/index",{"title":136,"path":137,"stem":138},"テーブル","/modules/table","07.modules/01.table",{"title":140,"path":141,"stem":142},"ドキュメントツリー","/modules/document","07.modules/02.document",{"title":144,"path":145,"stem":146},"AIチャット","/modules/ai","07.modules/03.ai",{"title":148,"path":149,"stem":150},"認証・権限","/modules/auth","07.modules/04.auth",{"title":152,"path":153,"stem":154},"AI取込","/modules/organize","07.modules/05.organize",{"title":156,"path":157,"stem":158},"ストレージ","/modules/storage","07.modules/06.storage",{"title":160,"path":161,"stem":162},"NAS同期","/modules/sync","07.modules/07.sync",{"title":164,"path":165,"stem":166},"ワークスペース","/modules/workspace","07.modules/08.workspace",{"title":168,"path":169,"stem":170},"テナントとメンバーシップ","/modules/tenant-membership","07.modules/09.tenant-membership",{"title":172,"path":173,"stem":174},"検索","/modules/search","07.modules/10.search",{"title":176,"path":177,"stem":178},"表示ビュー","/modules/display","07.modules/11.display",{"title":180,"path":181,"stem":182},"テンプレート","/modules/template","07.modules/12.template",{"title":184,"path":185,"stem":186},"メール","/modules/mail","07.modules/13.mail",{"title":188,"path":189,"stem":190},"電話","/modules/phone","07.modules/14.phone",{"title":192,"path":193,"stem":194},"リアルタイム","/modules/realtime","07.modules/15.realtime",{"title":196,"path":197,"stem":198,"children":199},"Infra And Deploy","/infra-and-deploy","08.infra-and-deploy",[200,203,207],{"title":201,"path":197,"stem":202},"インフラとデプロイ","08.infra-and-deploy/index",{"title":204,"path":205,"stem":206},"環境の種類","/infra-and-deploy/environments","08.infra-and-deploy/01.environments",{"title":208,"path":209,"stem":210},"セルフホスト構成","/infra-and-deploy/self-host","08.infra-and-deploy/02.self-host",{"title":212,"path":213,"stem":214,"children":215},"docs-map","/docs-map","09.docs-map/index",[216],{"title":212,"path":213,"stem":214},{"id":218,"title":80,"body":219,"description":695,"extension":696,"meta":697,"navigation":698,"path":81,"seo":699,"stem":82,"__hash__":700},"docs/04.backend/03.testing.md",{"type":220,"value":221,"toc":685},"minimark",[222,225,234,249,333,336,340,363,440,467,475,495,499,552,555,565,607,618,622,634,637,641,666,670,681],[223,224,80],"h1",{"id":80},[226,227,229,233],"h2",{"id":228},"gradlew-test-は直接叩けない",[230,231,232],"code",{},"./gradlew test"," は直接叩けない",[235,236,237,245,246,248],"p",{},[238,239,240,241,244],"strong",{},"バックエンドのテスト実行は ",[230,242,243],{},"/backend-test-reports"," skill 経由でのみ行います。"," ",[230,247,232],{}," を直接実行するのは deny 設定されています。理由は単純で、テストは Gradle タスクが複数に分かれていて（後述）、どれをどう実行して結果をどう読むかを skill 側に集約しているためです。",[250,251,256],"pre",{"className":252,"code":253,"language":254,"meta":255,"style":255},"language-bash shiki shiki-themes github-light github-dark","# skill 経由（これだけが正しい実行経路）\n.claude/skills/backend-test-reports/test.sh run --unit\n.claude/skills/backend-test-reports/test.sh run --integration --module tag\n.claude/skills/backend-test-reports/test.sh run --tests \"*TagServiceTest\"\n\n# 直接叩くのは NG（deny される）\n./gradlew test\n","bash","",[230,257,258,267,282,298,311,318,324],{"__ignoreMap":255},[259,260,263],"span",{"class":261,"line":262},"line",1,[259,264,266],{"class":265},"sJ8bj","# skill 経由（これだけが正しい実行経路）\n",[259,268,270,274,278],{"class":261,"line":269},2,[259,271,273],{"class":272},"sScJk",".claude/skills/backend-test-reports/test.sh",[259,275,277],{"class":276},"sZZnC"," run",[259,279,281],{"class":280},"sj4cs"," --unit\n",[259,283,285,287,289,292,295],{"class":261,"line":284},3,[259,286,273],{"class":272},[259,288,277],{"class":276},[259,290,291],{"class":280}," --integration",[259,293,294],{"class":280}," --module",[259,296,297],{"class":276}," tag\n",[259,299,301,303,305,308],{"class":261,"line":300},4,[259,302,273],{"class":272},[259,304,277],{"class":276},[259,306,307],{"class":280}," --tests",[259,309,310],{"class":276}," \"*TagServiceTest\"\n",[259,312,314],{"class":261,"line":313},5,[259,315,317],{"emptyLinePlaceholder":316},true,"\n",[259,319,321],{"class":261,"line":320},6,[259,322,323],{"class":265},"# 直接叩くのは NG（deny される）\n",[259,325,327,330],{"class":261,"line":326},7,[259,328,329],{"class":272},"./gradlew",[259,331,332],{"class":276}," test\n",[235,334,335],{},"Claude Code（AI エージェント）だけでなく、人間が手元で確認する場合もこの skill を使うのが安全です。テストタイプの指定・モジュール絞り込み・結果サマリ表示まで一貫して面倒を見てくれます。",[226,337,339],{"id":338},"unit-guard-integration-の区分","unit / guard / integration の区分",[235,341,342,345,346,245,349,245,352,355,356,362],{},[230,343,344],{},"backend/src/test/kotlin/com/astarworks/astarmanagement/"," はパッケージ単位で大まかに ",[230,347,348],{},"unit/",[230,350,351],{},"integration/",[230,353,354],{},"architecture/"," に分かれていますが、実行タスクの分割は ",[238,357,358,361],{},[230,359,360],{},"@Tag"," だけでなくクラス名の suffix"," で決まります。",[364,365,366,382],"table",{},[367,368,369],"thead",{},[370,371,372,376,379],"tr",{},[373,374,375],"th",{},"タスク",[373,377,378],{},"対象",[373,380,381],{},"特徴",[383,384,385,406,424],"tbody",{},[370,386,387,393,403],{},[388,389,390],"td",{},[230,391,392],{},"unitTest",[388,394,395,398,399,402],{},[230,396,397],{},"@Tag(\"unit\")"," のうち、以下の 7 suffix を",[238,400,401],{},"除いた","もの",[388,404,405],{},"モック依存の高速テスト。ヒープ 2g",[370,407,408,413,421],{},[388,409,410],{},[230,411,412],{},"guardTest",[388,414,415,417,418],{},[230,416,397],{}," のうち、以下の 7 suffix",[238,419,420],{},"だけ",[388,422,423],{},"ArchUnit ベースのアーキテクチャ検証。ヒープ 4g（ArchUnit の import cache が重い）",[370,425,426,431,437],{},[388,427,428],{},[230,429,430],{},"integrationTest",[388,432,433,436],{},[230,434,435],{},"IntegrationTestBase"," を継承したテスト",[388,438,439],{},"実 DB (TestContainers) + 実 API 呼び出し",[235,441,442,444,445,245,448,245,451,245,454,245,457,245,460,245,463,466],{},[230,443,412],{}," の 7 suffix: ",[230,446,447],{},"*ArchitectureTest",[230,449,450],{},"*GuardTest",[230,452,453],{},"*BoundaryTest",[230,455,456],{},"*SnapshotTest",[230,458,459],{},"*CoverageTest",[230,461,462],{},"*ContractTest",[230,464,465],{},"*ParityTest","。実例:",[250,468,473],{"className":469,"code":471,"language":472},[470],"language-text","architecture/ModuleBoundaryTest.kt              # *BoundaryTest\narchitecture/TenantScopedTableContractTest.kt    # *ContractTest\narchitecture/ErrorCodeCatalogI18nParityTest.kt   # *ParityTest\narchitecture/NasSyncBypassGuardTest.kt           # *GuardTest\n","text",[230,474,471],{"__ignoreMap":255},[235,476,477,478,481,482,485,486,494],{},"⚠️ ",[259,479,480],{},"自衛"," クラス名が ",[230,483,484],{},"FooInvariantTest"," のように、意図はアーキテクチャ検証でもこの 7 suffix のどれにも当てはまらないと、",[238,487,488,490,491,493],{},[230,489,412],{}," ではなく ",[230,492,392],{}," に無言で分類されます","。新しく ArchUnit / 不変条件系のテストを書くときは、7 suffix のどれかを名前に含めてください。",[226,496,498],{"id":497},"integration-テストの規約","Integration テストの規約",[500,501,502,523,532],"ul",{},[503,504,505,506,508,509,515,516,522],"li",{},"基底クラスは ",[230,507,435],{},"。",[238,510,511,514],{},[230,512,513],{},"@Transactional"," を integration テストに付けない"," — 付けると ArchUnit ガードが落ちます ",[259,517,518,519],{},"番人: ",[230,520,521],{},"IntegrationTestTransactionArchitectureTest","。実際の commit タイミングやトランザクション境界を検証するのが integration テストの役割なので、テスト自体をトランザクションで包んでしまうと意味が崩れます。",[503,524,525,527,528,531],{},[259,526,480],{}," integration テストから直接 SQL を書かない。ガードはありませんが、",[230,529,530],{},"RepositoryImpl"," 経由でテストすることで実際のアプリケーションパスを検証できます。",[503,533,534,535,537,538,541,542,541,545,541,548,551],{},"RLS が絡むテストは ",[230,536,435],{}," の ",[230,539,540],{},"withRls"," / ",[230,543,544],{},"withServiceRls",[230,546,547],{},"withNullRls",[230,549,550],{},"withRawRls"," ヘルパーを使ってテナント・ユーザーコンテキストを設定します。",[226,553,554],{"id":554},"スコープ限定実行が既定",[235,556,557,564],{},[238,558,559,560,563],{},"フルスイート（",[230,561,562],{},"test.sh run --all"," 相当）は最終検証と CI だけで実行します。"," 実装中・修正中は必ずスコープを絞ってください。",[250,566,568],{"className":252,"code":567,"language":254,"meta":255,"style":255},"# 触っているモジュールだけ\n.claude/skills/backend-test-reports/test.sh run --integration --module tag\n\n# 特定クラス・特定メソッドだけ\n.claude/skills/backend-test-reports/test.sh run --tests \"*TagServiceTest.shouldCreateTag*\"\n",[230,569,570,575,587,591,596],{"__ignoreMap":255},[259,571,572],{"class":261,"line":262},[259,573,574],{"class":265},"# 触っているモジュールだけ\n",[259,576,577,579,581,583,585],{"class":261,"line":269},[259,578,273],{"class":272},[259,580,277],{"class":276},[259,582,291],{"class":280},[259,584,294],{"class":280},[259,586,297],{"class":276},[259,588,589],{"class":261,"line":284},[259,590,317],{"emptyLinePlaceholder":316},[259,592,593],{"class":261,"line":300},[259,594,595],{"class":265},"# 特定クラス・特定メソッドだけ\n",[259,597,598,600,602,604],{"class":261,"line":313},[259,599,273],{"class":272},[259,601,277],{"class":276},[259,603,307],{"class":280},[259,605,606],{"class":276}," \"*TagServiceTest.shouldCreateTag*\"\n",[235,608,609,610,613,614,617],{},"理由は 2 つあります。1 つは単純にフィードバックが速いこと。もう 1 つは、",[230,611,612],{},"main"," の baseline に",[238,615,616],{},"既知の赤","（後述）が一定数あり、フルスイートを回すたびにその既知の赤と自分の変更由来の赤を毎回仕分けるコストが発生するためです。",[226,619,621],{"id":620},"既知の-baseline-red自分の変更が原因ではない","既知の baseline red（自分の変更が原因ではない）",[235,623,624,626,627,629,630,633],{},[230,625,612],{}," の時点で、unit テスト 27 件（6 クラス）の失敗と ",[230,628,392],{}," タスク自体のハング（想定所要時間 20 分）、integration テスト 14 件（8 クラス、RLS 分離系テストを含む）の失敗が既知として残っています。",[230,631,632],{},"DefaultAiMemberProvisioningIntegrationTest"," はいわゆる test-first の赤（advisory lock がまだ実装されていない設計上のプレースホルダ）です。",[235,635,636],{},"自分の変更がこれらのクラスに触れていないのに赤が出ても、それは既存の baseline であって、あなたが直したり原因調査したりする対象ではありません。ただし「自分の変更がこの baseline を悪化させていないか」（新しい失敗が増えていないか）は確認してください。",[226,638,640],{"id":639},"pr-ゲートと-ci","PR ゲートと CI",[235,642,643,644,647,648,651,652,655,656,541,658,541,660,662,663,665],{},"CI 上のプルリクエストは ",[230,645,646],{},"prTest","（10 分以内を目標にした高シグナルサブセット、",[230,649,650],{},"@Tag(\"pr\")","）と ",[230,653,654],{},"integrationGuardTest","（DB レベルの RLS/認可整合性ゲート）を実行します。フルの ",[230,657,392],{},[230,659,412],{},[230,661,430],{}," は ",[230,664,612],{}," への push・夜間・手動実行のタイミングで走ります。",[226,667,669],{"id":668},"migration-を追加するテストの注意","Migration を追加するテストの注意",[235,671,672,673,676,677,680],{},"新しい Flyway migration を追加した状態で integration テストを走らせる場合は ",[230,674,675],{},"TESTCONTAINERS_REUSE_ENABLE=false"," を付けて実行してください（",[230,678,679],{},"test.sh"," に環境変数として渡します）。既存の TestContainers を使い回すと、追加した migration が適用されていない古いスキーマに対してテストが走ってしまいます。",[682,683,684],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":255,"searchDepth":269,"depth":269,"links":686},[687,689,690,691,692,693,694],{"id":228,"depth":269,"text":688},"./gradlew test は直接叩けない",{"id":338,"depth":269,"text":339},{"id":497,"depth":269,"text":498},{"id":554,"depth":269,"text":554},{"id":620,"depth":269,"text":621},{"id":639,"depth":269,"text":640},{"id":668,"depth":269,"text":669},"unit / guard (ArchUnit) / integration の区分と、/backend-test-reports skill が唯一のテスト実行経路であること。","md",{},{"title":80},{"title":80,"description":695},"EK0v7f4hnXraV8R21X50oWbF6HEgLw8orz-u8qr-Nc4",[702,704,705,707,708,709,710,711,712,713,714,715,717,718,719,720,721,723,724,725,726,727,729,731,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,751,752,753,754],{"path":13,"title":703},"Astar とは何か（5分で）",{"path":17,"title":16},{"path":6,"title":706},"ようこそ",{"path":29,"title":28},{"path":33,"title":32},{"path":37,"title":36},{"path":21,"title":25},{"path":49,"title":48},{"path":53,"title":52},{"path":57,"title":56},{"path":61,"title":60},{"path":41,"title":716},"システムアーキテクチャ",{"path":73,"title":72},{"path":77,"title":76},{"path":81,"title":80},{"path":85,"title":84},{"path":65,"title":722},"バックエンドガイド",{"path":97,"title":96},{"path":101,"title":100},{"path":105,"title":104},{"path":109,"title":108},{"path":89,"title":728},"フロントエンドガイド",{"path":121,"title":730},"Go agent — NAS 同期エージェント",{"path":125,"title":732},"astar CLI",{"path":113,"title":117},{"path":137,"title":136},{"path":141,"title":140},{"path":145,"title":144},{"path":149,"title":148},{"path":153,"title":152},{"path":157,"title":156},{"path":161,"title":160},{"path":165,"title":164},{"path":169,"title":168},{"path":173,"title":172},{"path":177,"title":176},{"path":181,"title":180},{"path":185,"title":184},{"path":189,"title":188},{"path":193,"title":192},{"path":129,"title":750},"モジュール索引",{"path":205,"title":204},{"path":209,"title":208},{"path":197,"title":201},{"path":213,"title":755},"docs/ 地図",1785452455049]