見出し画像

[Rails] RSpecでカバレッジを可視

はじめに


こんにちは、横浜事業所のF.Tです。
最近、Railsで作成されたプロジェクトの単体テストにRSpecを導入しました。
その際に、テストのカバレッジを取得&可視化するためにsimplecovというgemを追加しました。テストについては設計もコーディングもほぼほぼ経験がなく、有識者も周りにいなかったため調べつつなんとか実装を行いました。
というわけで今回は、RSpecの導入とカバレッジ取得についてまとめていきたいと思います。
超ざっくりいうと、「Rubyでテスト自動化のためのコードを書いて、ちゃんとテストできているか可視化して確認する」 ということをしていきます。

RSpecとは


そもそもRSpecとはなんぞやというところを触れます。
RSpecとは、RubyやRuby on Railsで作成されたクラスやメソッドをテストするためのGemパッケージです。
以下公式では、

Behaviour Driven
Development for Ruby.
Making TDD Productive and Fun.

と記載してあることから、TDD(テスト駆動開発)・BDD(振る舞い駆動開発)を支援するためのツールとして存在しています。
言語はもちろんRubyが使用されています。

導入方法


上記のGitHubを参考に対象のRailsのバージョンに合わせたRSpecのgemをインストールします。今回は、既存でRailsアプリがある前提で進めていきます。
Gemfileに下記コードを追加しましょう。

group :development, :test do
  gem 'rspec-rails', '~> 対象version'
end

続いてRSpecのgemパッケージをインストールします。

$ bundle install

gemがインストールできたらRSpecの初期ファイルをインストールします。

$ rails generate rspec:install

以上でRSpecの準備ができました。実際の使用についてはカバレッジ取得の説明の際に触れます。

カバレッジとは


カバレッジとは
「所定の網羅条件がテストによってどれだけ実行されたかを割合で表したもの」です。
テストコードにおけるカバレッジとは、コード網羅率を意味しています。
テストコードが、テスト対象のメソッド等を本当に実行しているのか(網羅しているのか)を計測するために使用します。このカバレッジを取得することで、テストの品質を定量的に測ることができます。

またカバレッジの中でもレベルが細分化されており、
命令網羅(C0 or SC)
分岐網羅(C1 or BC)
条件網羅(C2 or CC)
判定条件/条件網羅(DC/CC)
複合条件網羅(MCC)
経路組み合わせ網羅(path coverage)
があります。
詳しくは以下のSHIFTのメディアやITmediaエンタープライズの情報システム用語事典の参考リンクを参照ください。

RSpecでのカバレッジ取得について


カバレッジ=コード網羅率
と述べましたが、テスト対象のコードがどれだけ網羅されているかを可視化できるパッケージがsimplecovです。

RSpecでテストを実行すると、htmlファイルが作成され、カバレッジが確認できます。

準備

simplecovのインストールは、まずGemfileに以下を記述します。

gem 'simplecov', require: false, group: :test

そしてbundle installを実行します。

インストールしただけだとカバレッジはまだ取得できないので、spec_helper.rbの最上部に以下を記述します。

require 'simplecov'
SimpleCov.start

これでカバレッジ取得の準備はOKです。

テストを書いてカバレッジ取得してみる

では実際に簡単なテストと実施し、カバレッジを見ていきましょう。
まずは以下の簡単なUser classを作成します。

user.rb

class User < ApplicationRecord

  def initialize(attributes = {})
    @name = attributes[:name]
    @age = attributes[:age]
  end

  def introduction
    if @age < 18
      "#{@name}は未成人です。"
    else
      "#{@name}は成人です。"
    end
  end

end

このclassをテストしてカバレッジを取得します。
spec/models/user_spec.rbに対象のテストコードを書いていきます。

user_spec.rb

RSpec.describe User do

  describe '#introduction' do
    let(:user) { User.new(**params) }
    let(:params) { { name: '未成人太郎', age: age } }

    context '18歳未満の場合' do
      let(:age) { 17 }
      it '未成人が返ること' do
        expect(user.introduction).to eq '未成人太郎は未成人です。'
      end
    end

  end

end

上記のテストコードはintroductionメソッドのテストを行なっており、

user.rb

if @age < 18
  "#{@name}は未成人です。"
else

age = 17 name = '未成人太郎は未成人です。'の時、つまりこの上記コードのif文がtrueのときの返り値が、期待値('未成人太郎は未成人です。')と等しいかどうかをテストしています。
では下記コマンドでテストを実行します。

$ bundle exec rspec

以下(ターミナルスクショ)が表示されました。上記のテストが期待値通り成功したことを表しています。

続いて上記のテストのカバレッジを見ていく前に、テストが失敗したときを見てみましょう。
同じintroductionメソッドに対して、

user_spec.rb

    # 年齢を変更
    context '20歳未満の場合' do
      let(:age) { 19 } 
      it '未成人が返ること' do
        expect(user.introduction).to eq '未成人太郎は未成人です。'
      end
    end

上記のように成人年齢の仕様が誤った'てい'でテストをしてみます。
結果は、以下となります。


テストが失敗しています。「テストコードでは成人年齢が20歳以上の仕様だと思って書いていたが、実際のUserモデルでは18歳以上の仕様だった」という現実でもなくはなさそうなケースであえて失敗させてみました。
添付画像内では、expected:でテストの期待値が、got:で実際のテスト対象メソッドの返り値が表示されています。

ではカバレッジを見ていきましょう。
先ほどのテストが成功した時、Coverage report generated ・・・・と表示が出ます。
この表示が出ていれば、coverageディレクトリが新しくプロジェクト内に作成されていることが確認できると思います。そのディレクトリ内の index.htmlから、カバレッジが確認できますので、見てみましょう。

この添付画像がカバレッジを可視化したindex.htmlになります。テスト実行時Userモデルのコードで通った部分が緑ライン、通っていない部分が赤ラインで表示されています。今回はifがfalseの場合に関してテストを記述していなかったため、赤で表示されています。

以下の通り、18歳以上の場合のテストも追加してあげると、Userモデルのカバレッジが100%となります。

user_spec.rb

    context '18歳未満の場合' do
      let(:age) { 17 }
      it '未成人が返ること' do
        expect(user.introduction).to eq '未成人太郎は未成人です。'
      end
    end

    context '18歳以上の場合' do
      let(:age) { 18 }
      it '成人が返ること' do
        expect(user.introduction).to eq '未成人太郎は成人です。'
      end
    end

ここまで簡単にですが、RSpecとsimplecovを導入し、実際にテストを実行してカバレッジを確認する所までを紹介しました。実際はカバレッジをただ100%にすれば良いわけではなく、「テスト対象だけをテストできているか」「テストコードが読みやすいか」「仕様に合ったテストが行えているか」等、意識しないといけないポイントは多いです。その辺のバランスをうまくとって、効率的に品質の高い開発ができるエンジニアになりたいものです。

参考


ALHについて知る



↓ ↓ ↓ 採用サイトはこちら ↓ ↓ ↓


↓ ↓ ↓ コーポレートサイトはこちら ↓ ↓ ↓


↓ ↓ ↓ もっとALHについて知りたい? ↓ ↓ ↓