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


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

このURLから参照できます。
ここではチュートリアルの作業リポジトリを使ってCIでテストカバレッジをとるまでの手順を記録します。

前提

  • Ruby on Rails チュートリアル第4版 を順番通り行う
  • Rubyのversionは2.6.3を使用
  • GitHubの公開リポジトリをCircleCIと連携
  • simplecovとCoverallsを使ってテストカバレッジを取得

CircleCIでrails testを回す

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

次に、CircleCI公式の手順に従い連携の設定を行います。
Language Guide: Ruby - CircleCI

具体的には、リポジトリに以下のような .circleci/config.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

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

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

gem 'spring', github: 'mattbrictson/spring', branch: 'honor-bundle-app-config'

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

simplecov

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

.gitignore:

coverage/

Gemfile:

group :test do
  ...
  gem 'simplecov'
end

test/test_helper.rb:

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

Coveralls

CoverallsはGitHubと連携して取得したカバレッジを可視化してくれるサービスです。
Ruby on Rails | Coveralls Docs

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

Gemfile:

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

test/test_helper.rb:

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

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

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

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

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

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

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

以上です。