はじめに
僕が執筆したRubyの入門書「プロを目指す人のためのRuby入門」では、Minitestを使って例題の実行結果をテストしています。
ですが、実際の現場ではMinitestではなく、RSpecを使っている場合も多いと思います。
そこで、この記事では「プロを目指す人のためのRuby入門」のテストコードを、筆者自らRSpecに書き換えてみます。
RSpecをまったく知らない方へ
RSpecの基本は詳しく説明しません。RSpecをまったく知らない、という方は、先に以下の記事を読んでからこの記事に戻ってきてください。
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita
※ただし、「RSpecの高度な機能」の項で説明している知識は今回使いません。
本記事は3部構成になっています
ボリュームが大きいので、本記事は3部構成になっています。
この記事では第3章から第6章までのテストコードをRSpecに書き換えます。
動画とソースコード
この記事の内容は動画(スクリーンキャスト)形式で解説しています。
細かい説明は口頭で話しているので、ぜひ動画もチェックしてください。
(録音状況が悪いため、ときどき大きなノイズが入ります。ごめんなさい🙏)
「プロを目指す人のためのRuby入門」のテストコードをRSpecに書き換える・その1
また、ソースコードはこちらにアップしています。
対象バージョン
この記事は以下の環境で動作確認しています。
- 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
.rspec
やspec_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版
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版
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版
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版
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' do
とdescribe '#to_ints' do
は、それぞれテストのグループ化をしています。前者は「to_hex
メソッドをテストするグループ」で、後者は「to_ints
メソッドをテストするグループ」です。
第5章 長さの単位変換プログラム
Minitest版
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版
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版
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を使わない場合)
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を使う場合)
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回の記事で書き換えていきます。