# テスト

> Source: https://www.ymotongpoo.com/works/adopting-erlang-ja/development/testing/


## Common Test

## Coverage

## Dialyzer

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

```erlang
-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にマッチしないマップになります。

```erlang
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_opts`を`rebar.config`に加えることで有効にできます。

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

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

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

```yaml
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](https://codecov.io)へレポートされるcoverを実行するプロジェクトの、CircleCIのワークフローページです。

![CircleCIのワークフロー成功例](circleci_ct_success_workflow.png)

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

![CircleCIのJUnit成功例](circleci_ct_junit_success.png)

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

![CircleCIの成果物一覧](circleci_ct_artifacts.png)

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

![Common TestのHTML出力](circleci_ct_html.png)

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

![CircleCIのJUnit失敗例](circleci_ct_junit_failure.png)


#### Microsoft's visual studio output
 https://github.com/ferd/trx

#### CirrusCI

#### Google Cloud Build

```yaml
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']
```

