Ruby
RSpec
プロを目指す人のためのRuby入門

【動画付き】「プロを目指す人のためのRuby入門」のテストコードをRSpecに書き換える・その1

はじめに

僕が執筆したRubyの入門書「プロを目指す人のためのRuby入門」では、Minitestを使って例題の実行結果をテストしています。
ですが、実際の現場ではMinitestではなく、RSpecを使っている場合も多いと思います。

そこで、この記事では「プロを目指す人のためのRuby入門」のテストコードを、筆者自らRSpecに書き換えてみます。

rubybook-mini.jpg

RSpecをまったく知らない方へ

RSpecの基本は詳しく説明しません。RSpecをまったく知らない、という方は、先に以下の記事を読んでからこの記事に戻ってきてください。

使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita
※ただし、「RSpecの高度な機能」の項で説明している知識は今回使いません。

本記事は3部構成になっています

ボリュームが大きいので、本記事は3部構成になっています。
この記事では第3章から第6章までのテストコードをRSpecに書き換えます。

動画とソースコード

この記事の内容は動画(スクリーンキャスト)形式で解説しています。
細かい説明は口頭で話しているので、ぜひ動画もチェックしてください。
(録音状況が悪いため、ときどき大きなノイズが入ります。ごめんなさい🙏)

「プロを目指す人のためのRuby入門」のテストコードをRSpecに書き換える・その1Screen Shot 2018-03-19 at 5.19.53.png

また、ソースコードはこちらにアップしています。

https://github.com/JunichiIto/ruby-book-codes/tree/rspec/ruby-book

対象バージョン

この記事は以下の環境で動作確認しています。

  • Ruby 2.4.1
  • RSpec 3.7.0

それでは以下が本編です。

セットアップ

gemコマンドを使ってRSpecをインストールします。

$ gem install rspec

テストコードを書きたいプロジェクトのルートディレクトリに移動し、rspec --initコマンドを実行すると、RSpecの実行に必要なファイルやディレクトリが作成されます。

$ rspec --init
create   .rspec
create   spec/spec_helper.rb

.rspecspec_helper.rbはRSpecを実行するための設定ファイルですが、今回はデフォルトのまま使うので説明は割愛します。

コンソールからrspecコマンドを実行し、以下のような結果になればセットアップ完了です。

$ rspec
No examples found.


Finished in 0.00038 seconds (files took 0.67611 seconds to load)
0 examples, 0 failures

セットアップ直後にはテストがありませんが、specディレクトリにテストコードがあれば、テストが実行されます。

第3章 FizzBuzzプログラム

Minitest版

test/fizz_buzz_test.rb
require 'minitest/autorun'
require './lib/fizz_buzz'

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 '4', fizz_buzz(4)
    assert_equal 'Buzz', fizz_buzz(5)
    assert_equal 'Fizz', fizz_buzz(6)
    assert_equal 'Fizz Buzz', fizz_buzz(15)
  end
end

RSpec版

spec/fizz_buzz_spec.rb
require './spec/spec_helper'
require './lib/fizz_buzz'

RSpec.describe 'Fizz Buzz' do
  it 'returns valid string' 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(4)).to eq '4'
    expect(fizz_buzz(5)).to eq 'Buzz'
    expect(fizz_buzz(6)).to eq 'Fizz'
    expect(fizz_buzz(15)).to eq 'Fizz Buzz'
  end
end

ポイント

  • 4行目のRSpec.describeでは、テスト対象のプログラムやクラスを記述します。
  • it 'returns valid string' doの部分では、プログラムの期待する振る舞いを記述しています。この場合は「(テスト対象のメソッドが)正しい文字列を返すこと」という内容になっています。
  • 英語が苦手な人はitに渡す文字列を日本語で書いても構いません(例:it '正しい文字列を返すこと' do)。
  • RSpecのexpect(A).to eq Bは、Minitestのassert_equal B, Aに対応します。

第4章 RGB変換プログラム

Minitest版

test/rgb_test.rb
require 'minitest/autorun'
require './lib/rgb'

class RgbTest < Minitest::Test
  def test_to_hex
    assert_equal '#000000', to_hex(0, 0, 0)
    assert_equal '#ffffff', to_hex(255, 255, 255)
    assert_equal '#043c78', to_hex(4, 60, 120)
  end

  def test_to_ints
    assert_equal [0, 0, 0], to_ints('#000000')
    assert_equal [255, 255, 255], to_ints('#ffffff')
    assert_equal [4, 60, 120], to_ints('#043c78')
  end
end

RSpec版

spec/rgb_spec.rb
require './spec/spec_helper'
require './lib/rgb'

RSpec.describe 'RGB' do
  describe '#to_hex' do
    it 'returns valid string' do
      expect(to_hex(0, 0, 0)).to eq '#000000'
      expect(to_hex(255, 255, 255)).to eq '#ffffff'
      expect(to_hex(4, 60, 120)).to eq '#043c78'
    end
  end

  describe '#to_ints' do
    it 'returns valid array' do
      expect(to_ints('#000000')).to eq [0, 0, 0]
      expect(to_ints('#ffffff')).to eq [255, 255, 255]
      expect(to_ints('#043c78')).to eq [4, 60, 120]
    end
  end
end

ポイント

  • describe '#to_hex' dodescribe '#to_ints' doは、それぞれテストのグループ化をしています。前者は「to_hexメソッドをテストするグループ」で、後者は「to_intsメソッドをテストするグループ」です。

第5章 長さの単位変換プログラム

Minitest版

test/convert_length_test.rb
require 'minitest/autorun'
require './lib/convert_length'

class ConvertLengthTest < Minitest::Test
  def test_convert_length
    assert_equal 39.37, convert_length(1, from: :m, to: :in)
    assert_equal 0.38, convert_length(15, from: :in, to: :m)
    assert_equal 10670.73, convert_length(35000, from: :ft, to: :m)
  end
end

RSpec版

spec/convert_length_spec.rb
require './spec/spec_helper'
require './lib/convert_length'

RSpec.describe 'Convert length' do
  it 'returns valid value' do
    expect(convert_length(1, from: :m, to: :in)).to eq 39.37
    expect(convert_length(15, from: :in, to: :m)).to eq 0.38
    expect(convert_length(35000, from: :ft, to: :m)).to eq 10670.73
  end
end

ポイント

(ここでは特に新しいトピックはありません。)

第6章 ハッシュ記法変換プログラム

Minitest版

test/convert_hash_syntax_test.rb
require 'minitest/autorun'
require './lib/convert_hash_syntax'

class ConvertHashSyntaxTest < Minitest::Test
  def test_convert_hash_syntax
    old_syntax = <<~TEXT
      {
        :name => 'Alice',
        :age=>20,
        :gender  =>  :female
      }
    TEXT
    expected = <<~TEXT
      {
        name: 'Alice',
        age: 20,
        gender: :female
      }
    TEXT
    assert_equal expected, convert_hash_syntax(old_syntax)
  end
end

RSpec版(letを使わない場合)

spec/convert_hash_syntax_spec.rb
require './spec/spec_helper'
require './lib/convert_hash_syntax'

RSpec.describe 'Convert hash syntax' do
  it 'converts old syntax to new syntax' do
    old_syntax = <<~TEXT
      {
        :name => 'Alice',
        :age=>20,
        :gender  =>  :female
      }
    TEXT
    expected = <<~TEXT
      {
        name: 'Alice',
        age: 20,
        gender: :female
      }
    TEXT
    expect(convert_hash_syntax(old_syntax)).to eq expected
  end
end

RSpec版(letを使う場合)

spec/convert_hash_syntax_spec.rb
require './spec/spec_helper'
require './lib/convert_hash_syntax'

RSpec.describe 'Convert hash syntax' do
  let(:old_syntax) do
    <<~TEXT
      {
        :name => 'Alice',
        :age=>20,
        :gender  =>  :female
      }
    TEXT
  end
  let(:expected) do
    <<~TEXT
      {
        name: 'Alice',
        age: 20,
        gender: :female
      }
    TEXT
  end
  it 'converts old syntax to new syntax' do
    expect(convert_hash_syntax(old_syntax)).to eq expected
  end
end

ポイント

  • RSpecではテストコード内に登場するローカル変数やインスタンス変数を、letと呼ばれるコードブロックに移動させることができます。
  • ここではit 'xxx' do ... endの中身をスッキリさせるために、letを使いました。
  • letについては前述の「使えるRSpec入門・その1」でも説明しているので、そちらの説明も参考にしてください。

まとめ

この記事では「プロを目指す人のためのRuby入門」の第2章から第6章までのテストコードをRSpecに書き換えました。
第7章以降のテストコードは第2回、および第3回の記事で書き換えていきます。