GitLabでテストコードをレビューしやすくする


はじめに

Increments × cyma (Ateam Inc.) Advent Calendar 2020 の8日目は、株式会社エイチーム EC事業本部の@hibiheionが担当します。
業務では主に自転車ECサイトcymaのバックエンドをRailsで書いています。

この記事はGitLabでテストコードをレビューしやすくする機能の紹介です。
ここではプログラミング言語としてRuby(Rails)、テストコードとしてRSpecを使用していますが、言語を限定した機能ではないので他のプログラミング言語でも使用可能です。

背景

みなさんはテストコードの運用で課題に感じていることはありませんか?
私がテストコードの運用で課題に感じていることのひとつにコードレビューの手間があります。
理由はテストコードのレビューではテストコードの書き方だけでなく、プロダクトコードをカバーするテストになっているかを確認する必要があるためです。
確認のためにマージリクエストのプロダクトコードとテストコードを見比べるというやり方をこれまで取っていたのですが、これだと単純に時間がかかりますし、複雑なメソッドだと見落としが起きてしまうこともあります。

こんな手間を減らしてくれるのが今回ご紹介するGitLabのTest Coverage Visualizationという機能です。

Test Coverage Visualizationとは

Test Coverage Visualization | GitLab

一言でいうとマージリクエストの行ごとにテストコードの有無を表示する機能です。
使用例を後でお見せしますが、この機能を使うとテストコードの有無がひと目でわかるようになります。

使用可能なGitLabのバージョン

この機能はバージョン12.9から利用可能ですが、バージョン13.4以降での利用をおすすめします。
理由はバージョン13.4より前のバージョンではパフォーマンスに問題があるためです。

This feature comes with the :coverage_report_view feature flag disabled by default. This feature is disabled due to some performance issues with very large data sets.

Test Coverage Visualization | GitLab(version 12.10)より

使用例

消費税を計算する簡単なプログラムを使って使用例をお見せします。
プロダクトコードはこちらです。

app/models/item.rb
class Item
  # 消費税を計算する
  # @param [Integer] price 本体価格
  # @param [Integer] tax_rate 整数の消費税率
  # @param [true,false] is_taxable 課税対象の場合はtrue、そうでない場合はfalse
  # @return [Integer] 消費税
  def self.calc_tax_price(price, tax_rate, is_taxable)
    if is_taxable
      (BigDecimal(price.to_s) * BigDecimal((tax_rate * 0.01).to_s)).ceil
    else
      0
    end
  end
end

次にテストコードはこちらです。
テストコードは課税対象の場合のテストケースのみ動くようにしています。

spec/models/item_spec.rb
require "rails_helper"

RSpec.describe Item, type: :model do
  describe ".calc_tax_price?" do
    context "課税対象の場合" do
      it "消費税を算出する" do
        tax = Item.calc_tax_price(10_000, 8, true)
        expect(tax).to eq 800
      end
    end

    context "課税対象ではない場合" do
      it "0を返す" do
        skip "後で書く"
      end
    end
  end
end

この2つのソースコードを含んだマージリクエストを作成します。
マージリクエストを作成した段階ではプロダクトコードは以下のような表示内容です。

これがマージリクエストに対するテストの実行が終わると以下のような表示内容に変わります。

テスト実行前の状態と比べると行番号の右側にバーが増えています。
このバーはその行のテストの有無を表していて、テストで通っている行には緑のバー、テストで通っていない行には茶色のバーを表示しています。
サンプルでは0を返すテストケースが通っていないので0を返す行が茶色のバーになっています。

このようにマージリクエスト上でテストコードの有無がひと目でわかるため、テストコードとプロダクトコードを見比べる手間を減らすことができます。
なお、テストコードの有無以外にもテストコードで確認が必要なところはありますので、テストコードとプロダクトコードを見比べる必要がなくなるわけではありません。

導入方法

以下の手順はGitLab-CIでマージリクエストの作成時にテストが動く状態を前提としています。

Rails + RSpecの環境でTest Coverage Visualizationの導入のために必要な修正は次の3点です。
なお、下記のソースコードではこの機能の導入で修正しない部分は省略しています。
例えば、GemfileでのRSpecの記述などです。

  • Gemのsimplecov-coberturaの追加
    • SimpleCovにCobertura XML形式のフォーマッターを追加するためのGem
Gemfile
group :test do
  gem "simplecov"
  gem "simplecov-cobertura"
end
  • SimpleCovの設定にCobertura XML形式のフォーマッターを追加
    • SimpleCov::Formatter::CoberturaFormatterを使用する
    • SimpleCovは複数のフォーマッターを指定できるので、他の形式のカバレッジレポートと同時に使用できる
spec/support/simple_cov.rb

require "simplecov"
require "simplecov-cobertura"

SimpleCov.start do
  formatters = [SimpleCov::Formatter::CoberturaFormatter, SimpleCov::Formatter::HTMLFormatter]
  formatter SimpleCov::Formatter::MultiFormatter.new(formatters)
end
  • gitlab-ci.ymlにCobertura XML形式のカバレッジレポートの出力を追加
    • RSpecの設定にartifactsを追加する
.gitlab-ci.yml
rspec:
  artifacts:
    paths:
      - coverage
    reports:
      cobertura: coverage/coverage.xml

以上の3点の修正でRails + RSpecの環境に導入できます。
Gitlab-CIですでにテストが動いている状態であればそれほど時間をかけずに導入できると思います。

ここではRubyを使っていますが、Cobertura XML形式のカバレッジレポートを出力できるプログラミング言語であればTest Coverage Visualizationを導入できます。

さいごに

Test Coverage Visualizationを導入した結果、テストコードのレビューの手間を減らすという当初の目的は達成できています。
それだけではなく、レビューを依頼する際にテストコードがないことが明確になるため「テストコードを書かなきゃ」という動機付けになる効果も期待できそうです。
ですので、この機能の導入はチームにテストコードを書く習慣を根付かせていくことにも大いにプラスになると私は考えています。

次回予告

Increments × cyma (Ateam Inc.) Advent Calendar 2020 の9日目は、Increments株式会社の@getty104さんがお送りします。