Edited at

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

More than 1 year has passed since last update.


はじめに

僕が執筆した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回の記事で書き換えていきます。