CircleCI CLI を使用したテスト分割

1+ year ago1 min read
Last updated • Read time
クラウド
This document is applicable to CircleCI クラウド
Server v4.x
This document is applicable to CircleCI Server v4.x
Server v3.x
This document is applicable to CircleCI Server v3.x

CircleCI では、並列実行するコンピューティング環境に対してテストを自動的に割り当てることができます。 CircleCI の設定ファイルで、parallelism キーを 1 より大きい値に設定すると、ジョブの実行環境について、同一の環境が複数スピンアップされます。

テスト分割機能を使用するには、parallelism キーに加えて、CircleCI CLI も必要です。 CLI の circleci tests glob コマンドと circleci tests split コマンドを使用して、テストスイートの定義と、複数の環境に対するテストの割り当てを行います。 実行時には CLI がジョブに自動で挿入されるので、これらの circleci tests コマンドは、特別な設定をすることなく利用できます。

1. テストファイルのグロブ

circleci tests glob を使用して、テストスイートを定義します。 テストファイルをグロブするには、以下のように glob コマンドに 1 つ以上のパターンを渡します。

circleci tests glob "tests/unit/*.java" "tests/functional/*.java"

CLI では、以下のパターンを使用したテストファイルのグロブをサポートしています。

  • * は、任意の文字シーケンスに一致します (パス区切り文字を除く)。

  • ** は、任意の文字シーケンスに一致します (パス区切り文字を含む)。

  • ? は、任意の文字シーケンスに一致します (パス区切り文字を除く)。

  • [abc] は、角かっこ内の任意の文字に一致します (パス区切り文字を除く)。

  • {foo,bar,…​} は、中かっこ内のいずれかの文字シーケンスに一致します。

**パターンマッチング(pattern-matching)の結果を確認するには、echo コマンドを使用します。

# ~/.circleci/config.yml
version: 2.1
jobs:
  test:
    docker:
      - image: cimg/node:20.3.0
    parallelism: 4
    steps:
      - run:
          command: |
            echo $(circleci tests glob "foo/**/*" "bar/**/*")
            circleci tests glob "foo/**/*" "bar/**/*" | xargs -n 1 echo

2. テストの分割

テストを分割するには、circleci tests split コマンドにテストのリストを渡します。

次のテスト分割用のオプションを使用できます。

  • オプション指定なし: 名前に基づいてアルファベット順に分割 (デフォルト)

  • --split-by=timings: タイミングデータに基づいて分割 (推奨)

  • --split-by=filesize: ファイルサイズに基づいて分割

a. 名前に基づいた分割 (デフォルト)

circleci tests split のデフォルトでは、--split-by フラグを使用しない場合、ファイル名またはクラス名のリストが渡されることを想定しており、テスト名に基づいてアルファベット順にテストを分割します。 ファイル名のリストは、以下に挙げる複数の方法で用意できます。

  • テストファイルのグロブをパイプする (前セクションのサンプルの方法)

circleci tests glob "test/**/*.java" | circleci tests split
  • テストファイル名を含むテキストファイルを作成する

circleci tests split test_filenames.txt
  • テストファイルへのパスを指定する

circleci tests split < /path/to/items/to/split

b. タイミングデータに基づいた分割

並列実行する Executor 全体でテストスイートを最適化するための最良の方法は、タイミングデータを使用してテストを分割することです。 この方法では、テストが最も均等に分割されるので、テストの所要時間が短くなります。

タイミングで分割するには、分割タイプ timingssplit-by フラグに付けて使用します。

circleci tests glob "**/*.go" | circleci tests split --split-by=timings

CircleCI では、テストスイートの実行が成功するたびに、 store_test_results ステップで指定されたパスのディレクトリからタイミングデータを保存します。 このタイミングデータには、ファイル名やクラス名ごとに各テストが完了するまでにかかった時間が含まれます。

タイミングデータがある場合には、その分析結果に基づき、テストが可能な限り均等に並列コンテナに分割されます。

JUnit の XML レポート

CircleCI にアップロードするテスト結果は、JUnit XML レポートにする必要があります。 以下のフォーマットのレポートであれば、CircleCI でテスト結果を解析してタイミングデータを取得し、自動テスト分割を実行できます。

  • file 属性が <testsuite> タグまたは <testcase> タグで設定されている

  • time 属性が <testcase> タグで設定されている

以下のサンプルスニペットに、CircleCI で解析可能な XML ファイルのフォーマットを示します。

<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="Mocha Tests" tests="3" failures="1">
  <testsuite tests="3">
    <testcase classname="foo1" name="ASuccessfulTest" time="10" file="src/__tests__/App.test.js" />
    <testcase classname="foo2" name="AnotherSuccessfulTest" time="5" file="src/__tests__/App.test.js" />
    <testcase classname="foo3" name="AFailingTest" time="1.1050" file="src/__tests__/App.test.js">
        <failure type="NotEnoughFoo"> details about failure </failure>
    </testcase>
  </testsuite>
</testsuites>

タイミングタイプの設定

CLI では、split コマンドの入力オプションに応じて、テスト分割の粒度 (分割基準をファイル名とクラス名のどちらにするかなど) を自動的に検出します。 ただし、テストカバレッジ出力のフォーマットによっては、--timings-type オプションを使用して、異なるタイミングタイプを選択する必要があります。 有効なタイミングタイプは以下のとおりです。

  • filename

  • classname

  • testname

  • autodetect

cat my_java_test_classnames | circleci tests split --split-by=timings --timings-type=classname

タイミングデータが見つからない場合のデフォルト値の設定

見つかったテスト結果が部分的なものである場合、データ不足のテストにはランダムな小さい値が割り当てられます。 このデフォルトの値は、--time-default フラグで上書きできます。

circleci tests glob "**/*.rb" | circleci tests split --split-by=timings --time-default=10s

タイミングデータのダウンロード

タイミングデータを手動で保存および取得するには、ジョブに store_artifacts ステップを追加します。

c. ファイルサイズに基づいた分割

CLI にファイルパスを指定すれば、ファイルサイズで分割することもできます。 分割タイプ filesizesplit-by フラグに付けて使用します。

circleci tests glob "**/*.go" | circleci tests split --split-by=filesize

3. 分割テストの実行

テストをグロブおよび分割しても、実際にテストが実行されるわけではありません。 テストのグループ化とテストの実行を結び付けるには、グループ化されたテストをファイルに保存してから、そのファイルをテストランナーに渡します。

circleci tests glob "test/**/*.rb" | circleci tests split > /tmp/tests-to-run
bundle exec rspec $(cat /tmp/tests-to-run)

ファイル /tmp/tests-to-run の内容は、$CIRCLE_NODE_INDEX$CIRCLE_NODE_TOTAL に応じて、コンテナごとに異なります。