Rubyの基礎を固めたい part2
こんにちは、チェリー本を使用してRubyの基礎を固める企画Part2です。
前回はこちらからどうぞ。
GitHubはこちら
では早速作業用のブランチを切って取り掛かりましょう!
##今回やること
前のチャプターで作成したFizzBuzzメソッドのテストコードをRspecを利用して書くことが今回の目的です。
記事冒頭にあるGitHubからでもコードを確認できますが、一応ここにも貼っておきます。
=begin
・3で割り切れる数字を引数に渡すと"Fizz"を返す
・5で割り切れる数字を引数に渡すと"Buzz"を返す
・15で割り切れる数字を引数に渡すと"FizzBuzz"を返す
・それ以外の数値は引数を文字列にして返す
=end
def fizz_buzz(integer)
if (integer % 3 == 0) && (integer % 5 == 0)
"FizzBuzz"
elsif integer % 3 == 0
"Fizz"
elsif integer % 5 == 0
"Buzz"
else
integer.to_s
end
end
fizz_buzz(1)
fizz_buzz(3)
fizz_buzz(5)
fizz_buzz(15)
fizz_buzz(22)
##Rspecの準備
前回でRspecのインストールは作成できているかと思います。(それ前提で話を進めていきます。)
おそらく作業ディレクトリにこのようなファイルが作成されているかと。
root/
┣ chapter2
┣ chapter3
┣ spec/
┃ └spec_helper.rb ←コレ!
┗.rspec ← コレ!
.rspecやspec_helper.rbはRspec用の設定ファイルです。
今回はどちらも弄りません。
ではテストコードを記述するファイルを作成しましょう。
$ cd spec
$ touch fizz_buzz_spec.rb
##Rspecでテストコードを書いていく
Rspecの基本構文は以下の通りです。
RSpec.describe 'テストの名前' do
it 'ここにテストの種類' do
処理内容
end
end
これを先ほど作成した fizz_buzz_spec.rb に当てはめていくと以下の様になります。
RSpec.describe 'FizzBuzz' do
it 'FizzBuzzメソッドが正常な動作をするか' do
expect(fizz_buzz(1)).to eq '1' # 期待する fizz_buzzメソッドの引数が1の時、引数を文字列として返す
expect(fizz_buzz(3)).to eq 'Fizz' # 期待する fizz_buzzメソッドの引数が3の倍数の時、Fizzを返す
expect(fizz_buzz(5)).to eq 'Buzz' # 期待する fizz_buzzメソッドの引数が5の倍数の時、Buzzを返す
expect(fizz_buzz(15)).to eq 'FizzBuzz' # 期待する fizz_buzzメソッドの引数が15の倍数の時、FizzBuzzを返す
expect(fizz_buzz(22)).to eq '22' # 期待する fizz_buzzメソッドの引数が22の倍数の時、22を返す
end
end
では次に処理の内容を見ていきましょう。
expect(fizz_buzz(1)).to eq '1'
ここで謎だと感じるのは、「expect」「.to」「eq」だと思います。
expectは「期待する」という意味があります。
expect(fizz_buzz(1))とすることで「fizz_buzzメソッドの引数が1の時、××を期待する」と訳せるわけですね!
次に「.to」です。
expect().to で「〜であることを期待する」と訳せます。
逆にexpect().not_to とすることで「××ではないことを期待する」と訳せます!
最後に「eq」です。
こいつはマッチャと呼ばれ、expect()に渡された値をどう料理するか決めます。(↑の部分でいう××)
「eq」は等しいかどうかを検証してくれるマッチャで、expect('hoge').to eq 'hoge'とすれば、「hogeがhogeと等しいことを期待する」という意味になります。
処理もかけたことですし、早速テストを実行してみましょう。
$ rspec #rspec spec/ファイル名でも実行可能
又は
$ rspec spec/fizz_buzz_spec.rb
実はこのままだとエラーが発生します。
uninitialized constant Object::Game (NameError)
fizz_buzz_spec.rbに以下のコードを追加します。
require 'spec_helper' #追加
require './chapter3/fizz_buzz' #追加 FizzBuzzメソッドを記述しているファイルの相対パスを記述
RSpec.describe 'FizzBuzz' do
it 'FizzBuzzメソッドが正常な動作をするか' do
〜(省略)〜
ではもう1度テストを実行してみましょう。
$ rspec spec/fizz_buzz_spec.rb
Finished in 0.00272 seconds (files took 0.10962 seconds to load)
1 example, 0 failures
テストが通りました!
ちなみにテストが失敗するとこんな感じのログが表示れます。
Failures:
1) FizzBuzz returns valid string
Failure/Error: expect(fizz_buzz(1)).to eq '1'
expected: "1"
got: nil
(compared using ==)
# ./spec/fizz_buzz_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.01304 seconds (files took 0.10494 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/fizz_buzz_spec.rb:6 # FizzBuzz returns valid string
パッと見ると「ウゲェ!」となるかもしれませんが、よく見ると失敗したエラー箇所が丁寧に案内されています。
確認をしたら、失敗している箇所のコードを修正します。
上の例だと「1を期待しているのに受け取った値はnilだよ」と言われていますね。
確認するとメソッドにミスがあったので修正しました。
## 最後に
今回はFizzBuzzメソッドという簡単なメソッドをRspecで書いてみました。
ただ今回のコードはベストプラクティスではありません。
というのも、テストはもっと分かりやすくカテゴライズすべきだからです。
幸いRspecにはそういった要件を解決してくれる機能が用意されています。
今回はその点を横着してしまいましたが、いずれRspecについても書いていきたいと思うので、その時はよろしくお願いします。
ちなみにチェリー本の著者である伊藤氏はRspecの参考書も出版されています!(すごい)
かなり分かりやすいので是非参考にしてみてください!
では今回はこの辺で。