テスト

この記事は英語の原文を日本語に翻訳したものです。原文: https://adoptingerlang.org/docs/development/testing/

翻訳元: adoptingerlang/adoptingerlang 2025-12-18(コミット 899008f

Common Test

Coverage

Dialyzer

service_discoveryからの例です。エンドポイントにport_nameを追加します。

-spec endpoint_from_json(unicode:unicode_binary(), map()) -> {ok, service_discovery:endpoint()} |
                                                             {error, term()}.
endpoint_from_json(ServiceName, #{<<"ip">> := IPString,
                                  <<"port">> := Port,
                                  <<"tags">> := Tags}) ->
    case inet:parse_address(binary_to_list(IPString)) of
        {ok, IP} ->
            {ok, #{service_name => ServiceName,
                   ip => IP,
                   port => Port,
                   tags => Tags}};
        {error, einval}=Error ->
            Error
    end;
endpoint_from_json(_, _) ->
    {error, bad_endpoint_json}.

戻り値にport_nameが欠けていると、service_discovery:endpoint()のspecにマッチしないマップになります。

apps/service_discovery_http/src/sdh_handler.erl
  42: The pattern 'ok' can never match the type {'error','bad_endpoint_json' | 'einval'}
 130: The pattern {'ok', Endpoint} can never match the type {'error','bad_endpoint_json' | 'einval'}

XRef

継続的インテグレーション

Docker Compose

CircleCI

CircleCIはGitHubのようなサービスとの統合に優れた、非常に柔軟なCIを提供しています。Erlangを扱う際にこの著者が気に入っているCircleCIの機能の1つが、テスト実行後のテスト成果物を配信する組み込みサポートです。Common TestがテストのレポートをHTMLで出力してくれるため、これは特に便利です。さらにCircleCIはJUnit形式の構造化されたXMLに基づいてテスト実行の情報を表示することもでき、CTはsurefireフックを使ってこの形式を出力できます。

surefireフックは、次のようなct_optsrebar.configに加えることで有効にできます。

%% generate junit xml report from test results
{ct_opts, [{ct_hooks, [cth_surefire]}]}.

CircleCIはRebar3プロジェクトを公式にはサポートしていませんが、Rebar3とCircleCIのキャッシュやアーティファクトストアを操作するために必要なツールを含んだErlangのDockerイメージをホストしています。しかしCircleCI Orbsのおかげで、CircleCI上でRebar3を使い始め、その独自の機能を活かすのは簡単です。CircleCI Orbsはワークフローの記述を簡単にする、再利用可能なコマンドやexecutor、jobです。Rebar3 Orbは、ビルド済みの依存関係のキャッシュや、CTのHTML出力のような成果物の移動を、CircleCIのアーティファクトコマンドを使って引き受けてくれます。

CircleCIは、実際にジョブへ割り当てられているよりもはるかに多くのCPUを積んだマシンでDockerイメージを実行します。Erlangはコンテナに割り当てられたCPU数にスケジューラの起動数を制限できないため、ホスト側から見えるCPU数と同じだけスケジューラを起動してしまいます。これは、VMが1つか2つのプロセッサしか使えないのに32個ほどのスケジューラをやりくりしようとして、リソースを無駄にする結果を招きます。rebar3実行時にErlangが起動するスケジューラ数を設定するには、環境変数ERL_FLAGSを使います。この変数にはerlに渡す必要のある引数を指定でき、この場合は"+S 2"となります。

version: 2.1

orbs:
  rebar3: tsloughter/rebar3@0.7.0

workflows:
  version: 2.1
  build_and_test:
    jobs:
    - rebar3/compile

    - rebar3/xref:
        requires:
        - rebar3/compile
    - rebar3/dialyzer:
        requires:
        - rebar3/compile
    - rebar3/ct:
        requires:
        - rebar3/compile

以下のスクリーンショットは、Common TestとDialyzer、xrefを並列に実行し、続けてcodecov.ioへレポートされるcoverを実行するプロジェクトの、CircleCIのワークフローページです。

CircleCIのワークフロー成功例

ワークフローのグラフでrebar3/ctのjobをクリックすると、そのジョブのページに移動します。ここにはジョブ内のステップの出力、JUnitのXMLに基づくテストサマリー、そしてジョブ完了後に保持された成果物のタブがあります。

CircleCIのJUnit成功例

成果物のタブを開くと、_build/test/logsの中身が確認できます。

CircleCIの成果物一覧

index.htmlへのリンクをたどると、https://498-59958463-gh.circle-artifacts.com/0/common_test/index.htmlのようなURLが新しいブラウザタブで開き、Common Testのすべてのテスト結果ページを閲覧できます。

Common TestのHTML出力

最後に、この画像はスイート内で失敗したテストケースについて、cth_surefireの出力から得られるテストサマリーの例です。

CircleCIのJUnit失敗例

Microsoft’s visual studio output

https://github.com/ferd/trx

CirrusCI

Google Cloud Build

steps:
- name: 'docker/compose:1.24.0'
  args: ['-f', 'docker-compose.yml', 'up', '-d']

- name: 'gcr.io/kaniko-project/executor:latest'
  args:
  - --target=releaser
  - --dockerfile=./Dockerfile.cb
  - --build-arg=BASE_IMAGE=$_BASE_IMAGE
  - --build-arg=RUNNER_IMAGE=$_RUNNER_IMAGE
  - --destination=gcr.io/$PROJECT_ID/service_discovery:tester-$BUILD_ID
  - --cache=true
  - --cache-ttl=48h

- name: 'gcr.io/cloud-builders/docker'
  args: ['run', '--network', 'workspace_sd_net', '-e', 'BUILD_ID=$BUILD_ID', '--entrypoint', 'rebar3', 'gcr.io/$PROJECT_ID/service_discovery:tester-$BUILD_ID', 'ct']