0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CircleCI テスト分割入門:`test-suites.yml` を 1 ファイル書いて並列実行する

0
Last updated at Posted at 2026-09-28

アプリケーションのテストやCI/CDは、開発の品質を支える工程です。テストが増えると、CIの結果待ちがボトルネックになります。

テストを減らせないケースでは、並列実行で1回あたりの時間を短くすることで対処することになります。

本記事ではCircleCIが標準でサポートする並列実行の方法である、タイミングベースの静的分割(static test splitting)について紹介します。CircleCIでのテスト分割の特徴は、テストコードや実行コマンドを大きく変更する必要がないことです。

この記事ではVitestを例に紹介します。ほかのテストツールの例について知りたい場合は、記事へのコメントで教えてください。

Vitestでのテストファイル列挙とJUnit生成をテストする

まずVitestを実行しているリポジトリで、JUnit XMLが生成できるかを確認してください。vitestでは--reporter=junitを使います。

% npx vitest run --reporter=junit
<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="2" failures="0" errors="0" time="0.01054925">
    <testsuite name="src/index.test.ts" timestamp="2026-09-25T07:07:34.330Z" hostname="cci-hidetakaokamoto-l4379" tests="2" failures="0" errors="0" skipped="0" time="0.01054925">
        <testcase classname="src/index.test.ts" name="GET / &gt; returns Hello Hono!" time="0.008839416">
        </testcase>
        <testcase classname="src/index.test.ts" name="GET /time &gt; returns current time as ISO 8601 JSON" time="0.001157292">
        </testcase>
    </testsuite>
</testsuites>

続いてvitest list --filesOnlyを実行します。このコマンドで、Vitestがどのテストファイルを実行するかの一覧が出ます。この2つのコマンドをあとでCI設定に使うので、エラーや無関係なログが混ざっていないかを確認してください。

% npx vitest list --filesOnly
src/index.test.ts

test-suites.ymlを作り、ローカルで検証する

次に.circleci/test-suites.ymlを作成します。runにテストコマンド、discoverにatom列挙、outputs.junitにJUnitの出力先を書きます。

---
name: ci tests
discover: npx vitest list --filesOnly
run: npx vitest run --reporter=junit --outputFile="<< outputs.junit >>" --bail 0 << test.atoms >>
outputs:
  junit: test-reports/junit.xml

discoverはテスト対象の一覧だけを出力します。無関係なパスが混ざると、意図しないテスト実行の原因になるので注意してください。

runは各並列ノードで走らせるコマンドです。割り当てられたテストファイル名などは、次のプレースホルダで渡します。

  • << test.atoms >> … そのノードに割り当てられたテストファイル(スペース区切り)
  • << outputs.junit >> … JUnit XMLの出力パス(outputs.junitと対応)

name・discover・run・outputsなど各キーの詳細については、testsuite configuration referenceで確認できます。

CircleCI CLI testsuite拡張を追加する

CircleCI CLIを最新にし、circleci extension install testsuiteで拡張を入れてください。バージョンはcircleci versionで確認できます。入れ方はThe CircleCI CLIを参照してください。CIコンテナ側の追加インストールは不要です。

その後、circleci testsuite doctorを実行します。

circleci testsuite doctor "ci tests"

doctorの必須チェックがすべてsuccessで、action itemsが空であることを確認してください。問題なければrunで、ローカルから同じコマンド経路を一度通します。

circleci testsuite run "ci tests"

これで、.circleci/test-suites.ymlのテストコマンドがローカルでも問題なく動くことを確認できました。

config.ymlにparallelismと testsuite を組み込む

次は定義したテストコマンドを、CIサービス上でのテスト実行ステップに追加しましょう。

circleci testsuite runをステップに追加し、parallelismを2以上にしてください。store_test_resultsのpathは、.circleci/test-suites.ymlのoutputs.junitに合わせます。パスがずれると、次回以降のタイミングデータが蓄積されません。

version: 2.1

jobs:
  test:
    docker:
      - image: cimg/node:22.22
    parallelism: 4
    steps:
      - checkout
      - run:
          name: Install dependencies
          command: npm ci
+      - run:
+          name: Run testsuite
+          command: circleci testsuite run "ci tests"
      - store_test_results:
          path: test-reports

workflows:
  version: 2
  ci-tests:
    jobs:
      - test

parallelismの取りうる値や制約は、Configuration Reference の parallelismに書いてあります。

CI で分割されたことを確認する

push後は、実行結果やログを確認しましょう。

1 回目: 件数と「タイミング無し」

CircleCIダッシュボードでジョブを開き、Tests タブの件数がローカル全件と一致するかを見てください。

スクリーンショット 2026-09-25 16.22.01.png

ログではPrimaryノードがdiscoverし、他ノードはWaiting for tests...と出ます。タイミングデータがまだないテストについては、次のようなログです。

スクリーンショット 2026-09-25 16.26.22.png

Autodetected classname timings for 1 tests.
No timing data (testname, classname or filename) found for 8 tests:

初回はタイミング履歴が少ないため、件数寄りの割り振りになります。ノード間の所要時間にも偏りが出やすく、並列化の効果はまだ限定的です。

2 回目: 新コミットで timing を見る

成功したジョブの Rerun(同じコミットの再実行)では、次のログとともに成功済みのtest atomがスキップされます。失敗したテストだけを再実行する動作です。

スクリーンショット 2026-09-25 16.30.24.png

Detected rerun, skipping previously successful test atoms
Selected 0 test atoms, Skipped 9 test atoms in 0s

Testsはすべてskippedになり、タイミングベース分割の観察には使えません。

設定を変えずに新しいコミットを pushしてフル実行してください。タイミング蓄積後は、次のようなログが出力されます。

スクリーンショット 2026-09-25 16.31.34.png

Autodetected classname timings for 9 tests.

遅いテストは単独ノードへ、速いテストは他ノードへと振り分けられます。

ダッシュボードの Timings タブで、ノードごとの所要時間の偏りが1回目より小さいかを確認してください。

スクリーンショット 2026-09-25 16.32.49.png

まとめ

Vitestのリポジトリなら、.circleci/test-suites.ymlにdiscover・run・outputsを書き、config.ymlでparallelismとcircleci testsuite runを足せば、タイミングベースの静的分割を始められます。ローカルでは拡張を入れたうえでdoctorとrunを通してください。CIではstore_test_resultsのパスをoutputs.junitに合わせます。

初回はタイミングが少なく、件数寄りの配分です。偏りが小さくなるのは、新しいコミットで実行した2回目以降に限られます。同じコミットのRerunは成功済みをスキップするため、timingの確認には使えません。

今回の設定をベースに、pushしたコードの差分と関係のあるテストだけを実行する「CircleCI Smarter Testing」を設定できます。詳細は以下の日本語ブログをご確認ください。

関連リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?