Ruby on Rails チュートリアルにてCIでカバレッジをとってみる

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Railsチュートリアル二周目の完走記念にスクショ <a href="https://t.co/zOGZtYrKRD">pic.twitter.com/zOGZtYrKRD</a></p>&mdash; sasaki (@yysaki) <a href="https://twitter.com/yysaki/status/1122866861681430528?ref_src=twsrc%5Etfw">2019年4月29日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


[未経験からRuby on Railsを学んで仕事につなげるまでの1000時間メニュー](https://qiita.com/saboyutaka/items/1a8c40e105e93ac6856a) の一環で、先日 [Ruby on Railsチュートリアル](https://railstutorial.jp/)の2周しました。
2周目をやるとき、単純に動かすだけでは面白みに欠けるので、図のようにCIでminitestのカバレッジを都度取るようにしてみました:

<img width="948" alt="スクリーンショット 2019-05-01 19.40.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50400/62df491c-a4e2-5730-e7ee-f5143b6eb697.png">


[このURL](ttps://coveralls.io/github/yysaki/sample_app_5.1?branch=master)から参照できます。
ここではチュートリアルの作業リポジトリを使ってCIでテストカバレッジをとるまでの手順を記録します。

## 前提

* [Ruby on Rails チュートリアル第4版](https://railstutorial.jp/?version=5.1) を順番通り行う
* Rubyのversionは2.6.3を使用
* GitHubの公開リポジトリをCircleCIと連携
* simplecovとCoverallsを使ってテストカバレッジを取得

## CircleCIでrails testを回す

本チュートリアルでGit管理を行う点が触れられていますが、ここでホスティングをBitbucketではなくGitHubを使ってみます。
このとき、安全にソースコードを公開するにあたってアクセスキートークンなどプロジェクト固有の情報をENVから取るように確認しています。

次に、CircleCI公式の手順に従い連携の設定を行います。
[Language Guide: Ruby - CircleCI](https://circleci.com/docs/2.0/language-ruby/)

具体的には、リポジトリに以下のような .circleci/config.yml を配置します。

``` yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.3-node
        environment:
          BUNDLE_PATH: vendor/bundle
          RAILS_ENV: test
    working_directory: ~/repo
    steps:
      - checkout

      - run:
          name: Configure Bundler
          command: |
            echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
            source $BASH_ENV
            gem install bundler

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

      - run:
          name: Bundle Install
          command: bundle check || bundle install --without development production

      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      - run:
          name: Run rails test
          command: |
            bundle exec rails db:migrate
            bundle exec rails test
```

`Configure Bundler` の箇所は、Bundlerを動かすためのワークアラウンドです。
2.0系のbundlerで生成されたGemfileを使用すると

```
You must use Bundler 2 or greater with this lockfile.
Exited with code 20
```

といったエラーを吐いてしまうため、 フォーラムで紹介されていたGemfile.lock記載のバージョンを使う対処を入れました。

[Using Bundler 2.0 during CI fails - Bug Reports - CircleCI Discuss](https://discuss.circleci.com/t/using-bundler-2-0-during-ci-fails/27411/3)

また、 `bundle install --without development` することで、spring のトラブルを回避するのも大事です。

- Use Bundler.with_original_env so that BUNDLER_APP_CONFIG is honored by mattbrictson https://github.com/rails/spring/pull/546

上記pull requestで修正されている不具合ですが、springのバージョンがbump upされる気配があまりなく、初めはgithubブランチをGemfileで指定する形でお茶を濁していました。

```
gem 'spring', github: 'mattbrictson/spring', branch: 'honor-bundle-app-config'
```
ですがこのことをRubyKaigi 2019のコード懇親会で相談したところ、springは開発環境のビルドを高速化するためにありCIでは不要だから、そもそも外せばいいのではと助言いただきました。
その結果上記対処をしてひと満足しています。

## simplecov

チュートリアルのminitestから行単位でどれだけ網羅されたのかカバレッジを取得してくれるツールとして [simplecov](https://github.com/colszowka/simplecov) を使用します。
READMEを参考に、以下のような設定を行いました

.gitignore:

```
coverage/
```

Gemfile:

``` ruby
group :test do
  ...
  gem 'simplecov'
end
```
 
test/test_helper.rb:

``` ruby
if ENV['RAILS_ENV'] == 'test'
  require 'simplecov'
  SimpleCov.start 'rails' do
    add_filter '/.bundle/'
    add_filter '/vendor/bundle/'
  end
end

ENV['RAILS_ENV'] ||= 'test'
...
``` 

この設定により、 `rails test` を実行すると coverage/配下にテストカバレッジのドキュメントが生成されます。

参考: [Ruby on Rails – gem SimpleCovを使ってテストカバレッジを計測｜Miningoo](https://miningoo.com/1980/)

## Coveralls

CoverallsはGitHubと連携して取得したカバレッジを可視化してくれるサービスです。
[Ruby on Rails | Coveralls Docs](https://docs.coveralls.io/ruby-on-rails)

最後にこちらのSIMPLECOV CUSTOMIZATIONの手順を参考に設定を行います。


Gemfile:

``` ruby
group :test do
  ...
  gem 'simplecov'
  gem 'coveralls', require: false
end
```

test/test_helper.rb:

``` ruby
if ENV['RAILS_ENV'] == 'test'
  require 'simplecov'
  require 'coveralls'

  SimpleCov.formatter = Coveralls::SimpleCov::Formatter
  SimpleCov.start 'rails' do
    ...
```

以上で設定完了です。
githubにpushすると自動テストが走り、テストカバレッジが収集されるようになりました。

図のようにチュートリアルの通りminitestをしっかりを書いた結果をみると、演習中タッチしてないapplication_cableなど除くと大半が100%となるのがわかります。

<img width="892" alt="スクリーンショット 2019-05-01 19.41.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50400/da250ab6-930a-8a4e-c983-d58276ae3f27.png">

チュートリアルのテストがしっかり網羅性のある手順を踏んでいることがわかり、ためになります。

一部0でも100%でもないものがありますが、例えばapp/model/user.rb ではBCｒｙｐｔの設定による分岐によるものでした。

<img width="876" alt="スクリーンショット 2019-05-01 19.44.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50400/ab3ad32b-a637-3eb9-4fc7-606877f54c5c.png">

必ずしもテストカバレッジは100%を目指すものではないとよく聞きますが、たしかにこの箇所はチェックする必要がなさそうです。


以上です。