メインコンテンツへ

テスト

./gradlew test は直接叩けない

バックエンドのテスト実行は /backend-test-reports skill 経由でのみ行います。 ./gradlew test を直接実行するのは deny 設定されています。理由は単純で、テストは Gradle タスクが複数に分かれていて(後述)、どれをどう実行して結果をどう読むかを skill 側に集約しているためです。

# skill 経由(これだけが正しい実行経路)
.claude/skills/backend-test-reports/test.sh run --unit
.claude/skills/backend-test-reports/test.sh run --integration --module tag
.claude/skills/backend-test-reports/test.sh run --tests "*TagServiceTest"

# 直接叩くのは NG(deny される)
./gradlew test

Claude Code(AI エージェント)だけでなく、人間が手元で確認する場合もこの skill を使うのが安全です。テストタイプの指定・モジュール絞り込み・結果サマリ表示まで一貫して面倒を見てくれます。

unit / guard / integration の区分

backend/src/test/kotlin/com/astarworks/astarmanagement/ はパッケージ単位で大まかに unit/ integration/ architecture/ に分かれていますが、実行タスクの分割は @Tag だけでなくクラス名の suffix で決まります。

タスク対象特徴
unitTest@Tag("unit") のうち、以下の 7 suffix を除いたものモック依存の高速テスト。ヒープ 2g
guardTest@Tag("unit") のうち、以下の 7 suffixだけArchUnit ベースのアーキテクチャ検証。ヒープ 4g(ArchUnit の import cache が重い)
integrationTestIntegrationTestBase を継承したテスト実 DB (TestContainers) + 実 API 呼び出し

guardTest の 7 suffix: *ArchitectureTest *GuardTest *BoundaryTest *SnapshotTest *CoverageTest *ContractTest *ParityTest。実例:

architecture/RlsDispatcherBoundaryArchitectureTest.kt # *ArchitectureTest
architecture/TenantScopedTableContractTest.kt    # *ContractTest
architecture/ErrorCodeCatalogI18nParityTest.kt   # *ParityTest
architecture/NasSyncBypassGuardTest.kt           # *GuardTest

⚠️ 自衛 クラス名が FooInvariantTest のように、意図はアーキテクチャ検証でもこの 7 suffix のどれにも当てはまらないと、guardTest ではなく unitTest に無言で分類されます。新しく ArchUnit / 不変条件系のテストを書くときは、7 suffix のどれかを名前に含めてください。

Integration テストの規約

  • 基底クラスは IntegrationTestBase。@Transactional を integration テストに付けない —実際の commit タイミングやトランザクション境界を検証するのが integration テストの役割なので、テスト自体をトランザクションで包んでしまうと意味が崩れます。
  • 自衛 integration テストから直接 SQL を書かない。ガードはありませんが、RepositoryImpl 経由でテストすることで実際のアプリケーションパスを検証できます。
  • RLS が絡むテストは IntegrationTestBase の withRls / withServiceRls / withNullRls / withRawRls ヘルパーを使ってテナント・ユーザーコンテキストを設定します。

module と class を同時に絞る

特定 module の integration class は、root application の全依存を保ったまま次の入口で実行します。

.claude/skills/backend-test-reports/test.sh run --integration \
  --module calendar --tests '*CalendarEventCommandIntegrationTest'

--module だけなら module の integration class 全体、--tests も指定した場合は明示した class だけを選びます。#4359 以降、integration class は :app が所有するため、入口は :app:integrationTest です。root の integration source set 全体を誤って起動しません。

test task の launch ごとに、長寿命 Postgres コンテナ内の astar_test_template を migration hash で再利用し、worker ごとの DB を CREATE DATABASE ... TEMPLATE astar_test_template で作ります。template が再構築された場合だけ Flyway が全 migration を走り、通常の class 起動では clone の作成だけです。template の再構築と clone は advisory lock で直列化されます。

期待 wall は箱・コンテナ状態・context cacheに依存します。変更前の非混雑実測は1 class 約85秒(うち Spring context + container + Flyway 約65秒)でした。現在の lane では integration/Testcontainers をローカル実行しないため、変更後の小・中・大 module の実測値は CI/nightly で採取します。採取時は Gradle/JVM、container start、Flyway(migration file 数と template migrate 秒)、context refresh/cache hit、test body を分け、org.springframework.test.context.cache=DEBUG の distinct context count と併記してください。実行ログには integration timing phase=... の行が出ます。gradle は task wall、jvm-startup は task から test config まで、container-start、flyway、template-clone、context-refresh、test-body が各内訳です。目標は first class <40秒、同一 module の second class <15秒です。

スコープ限定実行が既定

フルスイート(test.sh run --all 相当)は最終検証と CI だけで実行します。 実装中・修正中は必ずスコープを絞ってください。

# 触っているモジュールだけ
.claude/skills/backend-test-reports/test.sh run --integration --module tag

# 特定クラス・特定メソッドだけ
.claude/skills/backend-test-reports/test.sh run --tests "*TagServiceTest.shouldCreateTag*"

理由は 2 つあります。1 つは単純にフィードバックが速いこと。もう 1 つは、main の baseline に既知の赤(後述)が一定数あり、フルスイートを回すたびにその既知の赤と自分の変更由来の赤を毎回仕分けるコストが発生するためです。

既知の baseline red(自分の変更が原因ではない)

main の時点で、unit テスト 27 件(6 クラス)の失敗と unitTest タスク自体のハング(想定所要時間 20 分)、integration テスト 14 件(8 クラス、RLS 分離系テストを含む)の失敗が既知として残っています。DefaultAiMemberProvisioningIntegrationTest はいわゆる test-first の赤(advisory lock がまだ実装されていない設計上のプレースホルダ)です。

自分の変更がこれらのクラスに触れていないのに赤が出ても、それは既存の baseline であって、あなたが直したり原因調査したりする対象ではありません。ただし「自分の変更がこの baseline を悪化させていないか」(新しい失敗が増えていないか)は確認してください。

PR ゲートと CI

CI 上のプルリクエストは prTest(10 分以内を目標にした高シグナルサブセット、@Tag("pr"))と integrationGuardTest(DB レベルの RLS/認可整合性ゲート)を実行します。フルの unitTest / guardTest / integrationTest は main への push・夜間・手動実行のタイミングで走ります。

Migration を追加するテストの注意

新しい Flyway migration を追加した状態で clean-schema 経路を確認する最初の integration 実行には TESTCONTAINERS_REUSE_ENABLE=false を付けてください(test.sh に環境変数として渡します)。既存の Testcontainers を使い回すと、追加した migration が適用されていない古いスキーマを見逃す可能性があります。通常の実行では reuse を有効にし、Flyway が共有コンテナの schema history と差分 migration を管理します。