Ruby on RailsでRSpecとSimpleCovを使ってテストでカバレッジ取得までやってみた
こんにちは。 Ruby on Railsを触り始めたので、せっかくならTDDな開発で学習を進めてみようと思いテストコード+カバレッジ率取得を試してみました。
雑談ですが、ExcelやGoogleスプレドシートでテスト項目書を作成して手動でテストを実施していることもあると思いますが、なかなか労力が必要な作業でどうにかしたいと思いますね。 さらに当時作成したテスト項目書は使い捨てカイロ状態になりがちで、再び利用しようとしたとしもメンテナンスされておらず信用できないものになっていたりします。 テストコード+カバレッジ率取得ができることでKPI設定などをして自然とPDCAを回して維持していけるいいな。KPI設定やPDCAまわりであれこれはまた別の機会に。
完成した状態をGitHubで公開しておりますので、そちらもあわせて参照ください。 github.com
環境構築
- MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
- Docker version 20.10.12, build e91ed57
- Docker Compose version v2.2.3
- Ruby 3.1.0
- Rails 7.0.1
その他細かいパッケージはGitHubにて公開しているコードをご確認ください。
MinitestとRSpecの違い
Ruby on Railsにはデフォルトで利用できるMinitestがありますが、Rubyまわりよく聞くのはRSpecではないでしょうか。どのような違いがあるのか簡単にまとめるとできることは基本的に同じです。ただ、使い込んでいくことを考えると、RSpecの方が何かとメリットが多いように思います。 MinitestとRSpecは独立して使用できるため、得意不得意に応じて使い分けることもできなくはなさそうですね。
Minitestは、JUnitなどの古典的なTDDツールに馴染みがある人は親しみやすく、簡素なテストコード向け。
RSpecはドメイン固有言語でRubyの柔軟性を利用して「より読みやすい」テストを実現でき、豊富なアサーションライブラリやモックライブラリが利用できる。また、ドキュメントも充実している。
RSpecとは
Rubyプログラマー向けのビヘイビア駆動開発(BDD)ツール。BDDは、テスト駆動開発、ドメイン駆動設計、受入テスト駆動設計を組み合わせたソフトウェア開発手法です。特にTDDのドキュメントと設計に焦点を当てて、その部分を実行するものです。
RSpecは、以下の4つのライブラリに分割されて提供されています。本記事では、Rails利用を想定しているためrspec-rails
のみを利用します。
- rspec-core
- rspec-expectations
- rspec-mocks
- spec-rails
手順
rails new xxxx
でプロジェクトが作成されており、作成されたプロジェクト直下にいる状態からスタートします。
パッケージをインストール
rspecのパッケージをインストールします。
bundle add rspec-rails \ --group "development,test"
追加でテスト対象とするサンプルコードで利用するパッケージをインストールします。
bundle add bcrypt
RSpecの初期ファイル生成
rspec generate
コマンドを実行して初期ファイルを生成します。
g
は、generateの略です。
bundle exec rails g rspec:install
実行結果
$ bundle exec rails g rspec:install create .rspec exist spec create spec/spec_helper.rb create spec/rails_helper.rb
ファイルが作成されれば成功です。
テスト対象のサンプルコードを準備
テストコードを書く前にテスト対象とする方のコードを実装していきます。
Modelを作成
generateコマンド利用してmodeを作成しましょう。
bundle exec rails g model user
実行結果
$ rails generate model user invoke active_record create db/migrate/20220207045451_create_users.rb create app/models/user.rb invoke rspec create spec/models/user_spec.rb
spec/models/user_spec.rb
を見てみると無事にテストファイルも作成されました。
require 'rails_helper' RSpec.describe User, type: :model do pending "add some examples to (or delete) #{__FILE__}" end
マイグレートファイルからデータベースを作成
テストコードを実行するために簡単なサンプルコードを実装していきます。 メールとパスワードくらいの簡単なものを作成してみましょう。
generateコマンドを実行して作成されたapp/db/migrate/20220207045451_create_users.rb
に記載してください。
20220207045451
の部分は、その時々で変わってしまう値なので適宜読み替えてください。
class CreateUsers < ActiveRecord::Migration[7.0] def change create_table :users do |t| t.string :mail, null: false # 姓 t.string :hashed_password # パスワード t.timestamps end end end
次のコマンドを実行してDBを作成します。今回はSQLiteで簡易的に行います。
bundle exec rails db:create
実行結果
$ bundle exec rails db:create reated database 'db/development.sqlite3' Created database 'db/test.sqlite3'
次にテーブルを作成します。
bundle exec rails db:migrate
実行結果
$ bundle exec rails db:migrate 20220207045451 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0023s == 20220207045451 CreateUsers: migrated (0.0024s) =============================
Userモデルの実装
ユーザ情報が作成する際にパスワードはそのままの値を保持したくないので、ハッシュ化するという設定にします。 条件分岐があった方がカバレッジなどをみる際には差分を確認しやすいため、値がnilのケースの分岐を追加します。
generateコマンドを実行して作成されたapp/models/user.rb
に追記してください。
class User < ApplicationRecord def password=(password) if password.kind_of?(String) self.hashed_password = BCrypt::Password.create(password) else self.hashed_password = nil end end end
テスト
テスト対象のサンプルコードが準備できました。次にテストコードを実装していきましょう。
generateコマンドを実行して作成されたspec/models/user_spec.rb
に追記してください。
require 'rails_helper' RSpec.describe User, type: :model do describe "Hash password" do example "正常系" do member = User.new member.password = "baukis" expect(member.hashed_password).to be_kind_of(String) expect(member.hashed_password.size).to eq(60) end example "純正常系(nil)" do member = User.new(hashed_password: "x") member.password = nil expect(member.hashed_password).to be_nil end end end
記述が終わったら以下のコードで実行してみましょう。
$ bundle exec rspec
$ bundle exec rspec .. Finished in 0.9962 seconds (files took 3.84 seconds to load) 2 examples, 0 failures
何もエラーが出力されずに上記のような結果になれば成功です。
カバレッジ取得
今回は、SimpleCovを使ってカバレッジ率を取得します。
詳しい情報については、以下のリンクを参照してください。
必要なパッケージをインストール
bundle add simplecov --group ":test"
rspec:installで作成されたspec/rails_helper.rb
の先頭に次の2行を追記しましょう。
require 'simplecov' SimpleCov.start # This file is copied to spec/ when you run 'rails generate rspec:install' ・・・
追記が終わったら再びRSpecを実行してみましょう。先ほどと違い1行増えていると思います。
bundle exec rspec
実行結果
$ bundle exec rspec .. Finished in 0.34343 seconds (files took 3.36 seconds to load) 2 examples, 0 failures Coverage report generated for RSpec to /app/coverage. 39 / 39 LOC (100.0%) covered.
増えた行は、こちらです。
Coverage report generated for RSpec to /app/coverage. 39 / 39 LOC (100.0%) covered.
CLIで簡易的な出力を確認することもできますが、/coverage
配下に詳細なHTMLレポートが出力されているので、そちらを見てみるとどの行を通過したのかなどを詳しくみることができます。
無事にGUIでも確認ができたので、これで以上になります。