🤖

RSpecに入門してみた

2023/08/06に公開

はじめに

どうも、どすこいです。
就活が終わり卒業までに何か新しいチャレンジをしようと考えプログラミングの勉強を始めました。
自分が勉強していく中で気になったことなどをまとめていきます。
今回は、Rubyのテストでよく使われているテストフレームワークのRSpecについての記事になります。

対象読者

  • 私のように勉強したての初心者を対象にしています。
  • Rubyに入門した人
  • チェリー本のMinitestを行いRSpecを使ってみたい人

扱う範囲

今回は入門ですので、インストールの説明から、具体例として、RubyでFizzBuzzのプログラムを書き、説明をしていきます。Ruby on RailsでのControllerやModelのテストなどはまた別の記事に載せます。

RSpecとは

RSpecは、Rubyプログラムのためのテストフレームワークです。特に、振る舞い駆動開発(BDD: Behavior-Driven Development)のアプローチをサポートしており、自然言語に近い形でテストケースを記述することができます。これにより、テストコードがドキュメンテーションとしての役割も果たすようになります。

RSpecの主な特徴

  • 記述が直感的:RSpecのテストは「describe」や「it」などのメソッドを使用して、自然言語に近い形で記述されます。
  • 豊富なマッチャ:期待値と実際の値を比較するための多くのマッチャ(例: eq, be_truthy, includeなど)が提供されています。
  • カスタムマッチャの作成:独自のマッチャを定義することも可能です。
  • モックとスタブ:テストの際に外部の依存関係を模倣(モック)したり、特定のメソッドの戻り値を固定(スタブ)することができます。
  • タグ付け:テストケースやテストグループにタグを付けて、特定のタグのテストだけを実行することができます。

以下は、公式Docummentです。
https://rspec.info/

インストール方法

Ruby単体で使う場合(rubyとbundleのインストール方法は省略してます)
[手順]

  1. bundle initでGemfileを生成
  2. Gemfileに「gem “rspec”」を記述し、bundle install
  3. RSpec設定ファイルの生成
  4. spec_helper.rbの有効化

bundle initでGemfileを生成

terminal
bundle init

Gemfileに「gem “rspec”」を記述し、bundle install

Gemfile
gem “rspec”
terminal
bundle install

RSpec設定ファイルの生成

terminal
bundle exec rspec --init

上記のコマンドを実行すると、「.rspec」と「spec/spec_helper.rb」の2ファイルが生成されます。

spec_helper.rbの有効化
3.で生成されたspec_helper.rbの「=begin」と「=end」を削除し、spec_helper.rbを有効化する。

spec_helper.rb
# 中略
=begin //削除

# 中略  

  # Seed global randomization in this process using the `--seed` CLI option.
  # Setting this allows you to use `--seed` to deterministically reproduce
  # test failures related to randomization by passing the same `--seed` value
  # as the one that triggered the failure.
  Kernel.srand config.seed
=end //削除
end

実際に使ってみよう

今回は、チェリー本の最初の例題である「FizzBuzzプログラムを作成する」を具体例として用います。

ファイル構成

libファイルにfizzbuzzのプログラム
specにRSpecのファイル
testにMinitestのファイル

.
├── Gemfile
├── Gemfile.lock
├── README.md
├── lib
│   └── fizz_buzz.rb
├── spec
│   ├── fizz_buzz_spec.rb
│   └── spec_helper.rb
└── test
    └── fizz_buzz_test.rb

まずは、fizz_buzz.rbにfizzbuzzのプログラムを書きます。

fizz_buzz.rb
def fizz_buzz(n)
  if n % 15 == 0
    'FizzBuzz'
  elsif n % 3 == 0
    'Fizz'
  elsif n % 5 == 0
    'Buzz'
  else
    n.to_s
  end
end

続いて、Minitestの場合のテストコードを書きます。

fizz_buzz_test.rb
require 'minitest/autorun'
require_relative "../lib/fizz_buzz.rb"

class FizzBuzzTest < Minitest::Test
  def test_fizz_buzz
      assert_equal '1', fizz_buzz(1)
      assert_equal '2', fizz_buzz(2)
      assert_equal 'Fizz', fizz_buzz(3)
      assert_equal 'Buzz', fizz_buzz(5)
      assert_equal 'FizzBuzz', fizz_buzz(15)
  end
end

terminalで実行します。

terminal
ruby test/fizz_buzz_test.rb
出力
Run options: --seed 28700

# Running:

.

Finished in 0.000458s, 2183.4061 runs/s, 10917.0307 assertions/s.
1 runs, 5 assertions, 0 failures, 0 errors, 0 skips

テストが通っていることが分かります。

では続いて、RSpecのテストコードを書きます。

fizz_buzz_spec.rb
require_relative "../lib/fizz_buzz.rb"

RSpec.describe 'FizzBuzz' do
  it 'FizzBuzzの返り値正しいかを確認する' do
    expect(fizz_buzz(1)).to eq '1'
    expect(fizz_buzz(2)).to eq '2'
    expect(fizz_buzz(3)).to eq 'Fizz'
    expect(fizz_buzz(5)).to eq 'Buzz'
    expect(fizz_buzz(15)).to eq 'FizzBuzz'
  end
end

terminalで実行します。RSpecのテストコードを実行する際は、bundle exec rspecとします。

terminal
bundle exec rspec
出力
.

Finished in 0.02057 seconds (files took 0.11506 seconds to load)
1 example, 0 failures

テストが通っていることが分かります。

RSpecの基本的な使い方の説明

この節では、先ほどのfizz_buzz_spec.rbを見ながらRSpecの基本的な使い方について説明していきます。

基本的な構造
describe '何かのクラスやメソッドの説明' do
  context 'ある状況や条件の説明' do
    it '期待する振る舞いの説明' do
      expect(実際の値).to eq 期待する値
    end
  end
end

describe: テストのグループ化
context: 条件を分けたりするときに使う
it: example という単位にまとめる役割をする。it do ~ endの の中が正ければ全てexampleがパスしたことになります。
expect: expect(X).to eq Yの形で用います。この場合は、xがyと等しいになります。

fizz_buzz_spec.rbの場合の説明をしていきます。

fizz_buzz_spec.rb
require_relative "../lib/fizz_buzz.rb" //fizz_buzzファイルの読み込み

RSpec.describe 'FizzBuzz' do //FizzBuzzのテストを宣言する。
  it 'FizzBuzzの戻り値が正しいかを確認する' do //itでテストの内容を書く
    expect(fizz_buzz(1)).to eq '1'   //fizz_buzzの引数が1の時、戻り値が1
    expect(fizz_buzz(2)).to eq '2'
    expect(fizz_buzz(3)).to eq 'Fizz'
    expect(fizz_buzz(5)).to eq 'Buzz'
    expect(fizz_buzz(15)).to eq 'FizzBuzz'
  end
end

リファクタリングの余地はありますがこの記事では記載しません。

おまけ

.rspec--format documentationを追加すると、出力結果が見やすくなります。

terminal
FizzBuzz
  FizzBuzzの戻り値正しいかを確認する

Finished in 0.00112 seconds (files took 0.05465 seconds to load)
1 example, 0 failures

まとめ

  • 現場で使われているRSpecについての超基本的について記載しました
  • テストコードを書いて、よりエンジニアとして成長していきたいなと思いました。
  • 「チェリー本の例題を全てRSpecで書いてみた」という記事も続編で書きます。

参考にしたサイト

https://rspec.info/

https://techtechmedia.com/ruby-setup-rspec/

https://musclecoding.jp/

https://qiita.com/jnchito/items/42193d066bd61c740612

Discussion