CircleCI: parallelismを使うときにSimpleCovの結果をまとめ、Artifactsに置く

CircleCIでparallelismを使ってRspecを並列実行すると、SimpleCovの結果がそれぞれのcoverageディレクトリにばらばらに出力されてしまいます。これを1つにまとめ、さらにCircleCI上で結果のHTMLが見えるようにしたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308595/e2d13841-be5b-6ec2-4d87-507ab85dd633.png)

参考にしたページ:

- [CircleCI で並列実行したRSpecのカバレッジを Coveralls に送る](https://qiita.com/takeru0757/items/a07222700ece37e0562c)
- [Merging test runs under different execution environments](https://github.com/simplecov-ruby/simplecov#merging-test-runs-under-different-execution-environments)
- [Storing Build Artifacts - CircleCI](https://circleci.com/docs/2.0/artifacts/)

## 複数のジョブのテスト結果を1つのディレクトリにコピー

SimpleCovの結果は、coverageディレクトリの下のJSONファイル .resultset.jsonに 出力されます。以下の「Copy coverage results」のように、Rspecの実行後にJSONファイルを /tmp/coverage/.resultset-番号.json へコピーします。

さらにpersist_to_workspaceを使うと、/tmp/coverage 下のファイルをジョブ間で共有できます。RSpecの実行が終わるたびに、.resultset-番号.json がこのディレクトリに溜まっていきます。

なお、/tmp/coverage というディレクトリ名はてきとうです。

```yaml:.circleci/config.yml
  test:
    parallelism: 4
# 略
    steps:
# 略
      - run:
          name: rspec
          command: |
            bundle exec rspec --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format documentation \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split)
      - store_test_results:
          path: test_results

      - run:
          name: Copy coverage results
          command: |
            mkdir /tmp/coverage
            cp coverage/.resultset.json "/tmp/coverage/.resultset-${CIRCLE_NODE_INDEX}.json"
      - persist_to_workspace:
          root: /tmp/coverage
          paths:
            - .resultset-*.json
```

## SimpleCovの結果をまとめるタスク

最近のSimpleCovには、複数のJSONから1つのHTMLを出力する機能ができましたので、これをそのまま使うrakeファイルを書きます。

```ruby:lib/tasks/coverage_report.rake
namespace :coverage do
  desc "Collates all result sets generated by the different test runners"
  task :report do
    require 'simplecov'

    SimpleCov.collate Dir["/tmp/coverage/.resultset-*.json"], 'rails'
  end
end
```

## 並列テストが全部終わったら結果をまとめる

CircleCIのworkflowsの設定を行い、testジョブが全部終わったらreportジョブを走らせるようにします（以下の workflows - build_and_test - jobs - report の部分）。

reportジョブではrakeタスクの coverage:report を動かします。このとき、attach_workspace で 複数のJSONファイルが置かれた /tmp/coverage が使えるようにしておきます。これで、coverage の下にSimpleCovのHTMLができあがります。

さらに、store_artifacts を使うと coverage ディレクトリがCircleCIのArtifactsで一定期間保管され、ブラウザーから閲覧できるようになります。

```yaml:.circleci/config.yml
jobs:
  build:
# 略
  test:
# 略
  report:
    docker:
      - image: cimg/ruby:2.6.6-node
    steps:
      - checkout
      - ruby/install-deps:
          bundler-version: 2.1.4
      - attach_workspace:
          at: /tmp/coverage
      - run:
          name: Collates all result sets
          command: bundle exec rails coverage:report
      - store_artifacts:
          path: coverage

workflows:
  version: 2
  build_and_test:
    jobs:
      - build
      - test:
          requires:
            - build
      - report:
          requires:
            - test
```

## 今後の課題

Rails 6のパラレルテストはRspecで使えるのか、CircleCI上ではどうすべきなのか、調査する。

私のCircleCI記事:

- [CircleCI config.yml ひな型 Rails 6 / PostgreSQL / Rspec（orbと最新のimageの利用）](https://qiita.com/kazutosato/items/3f08a4da350a395f3bd2)
- [CircleCI config.yml ひな型 Rails 6 / PostgreSQL / Rspec](https://qiita.com/kazutosato/items/9817e746ae760fe27b6e)