この記事の目的
RSpecの取っ掛かりとして、簡単なRSpecを書いて実際に実行してみます。流れの中で説明も多少入っていますが、事細かく何を意味しているかなどの説明はあまりしません。あくまでまずRSpecを実行してみる、体験してみるところに重点をおきます。
##今回使用するメソッドの説明
文字列数字を足し算するメソッドを作ってみましょう。メソッドはint Add(string numbers)。
- メソッドは文字列の数字を引数(例:"1")に取る、カンマ区切りで複数の文字列の数字が取れる(例:"1,2,3")。
- 空の場合は0を返す
##RSpecを準備する
Gemfileにrspecを追加。bundle installを実行。
source "https://rubygems.org"
...
...
gem "rspec"
そして、specディレクトリ(なければmkdir specで作成)の直下にstring_calculator_spec.rbを作成します。これが今回使用するRSpecのファイルです。
describe StringCalculator do
end
RSpecでは、describeでclass、module、メソッドを記述します。describeブロックはrspecの処理の流れを記述するため、必ず最初に書かれます。
bundle exec rspecでrspecを実行してみます。すると下記のようなエラーが出てくるはずです。
これはまだStringCalculatorというクラスを作成していないからです。では、StringCalculatorクラスをlibの配下に作成します。
class StringCalculator
end
ここで、rspecのファイルにrequireを追加します。
require "string_calculator"
describe StringCalculator do
end
bundle exec rspecを実行します。
先ほどのエラーがなくなりました。これでコードを書く準備ができました。
##実際にRSpecを書いてみる
StringCalculatorのaddメソッドは空(empty)を受け入れてます。空を受け取ったら0を返す仕様です。まずはdescribeにaddを追加してみましょう。
require "string_calculator"
describe StringCalculator do
describe ".add" do
context "given an empty string" do
it "returns zero" do
expect(StringCalculator.add("")).to eql(0)
end
end
end
end
-
クラスメソッドのaddを記述するために、また別のdescribeを使います。そして慣例で、クラスメソッドはドット(.)のprefixを付けて(".add")、インスタンスメソッドにはdash(#)を付けます("#add")。
-
コンテキストブロックではaddメソッドが空だったら0を返すことを記述しています。contextはdescribeと意味的には同じなのですが、コードの可読性を向上させるために使われたりします。
-
itブロックはテストケースを記述するために使います。上記は、addメソッドに空を与えると0を返しますよという例です。
-
「expect(...).to」や「expect(...).not_to」は期待する(しない)結果を定義します。eqlはイコールの意味です(matcherと呼ぶらしい)。matcherはいろいろな書き方があるようです。参考:https://relishapp.com/rspec/rspec-expectations/v/3-1/docs/built-in-matchers
RSpecを書き終わったら、クラスにaddメソッドを追記しましょう。
class StringCalculator
def self.add(input)
0
end
end
追記後bundle exec rspecを実行します。
RSpecが通りました。
##1つの数字でaddメソッドをRSpecに通してみる
string_calculator_spec.rbを下記のように書き換えてみましょう。
require "string_calculator"
describe StringCalculator do
describe ".add" do
context "given '4'" do
it "returns 4" do
expect(StringCalculator.add("4")).to eql(4)
end
end
context "given '10'" do
it "returns 10" do
expect(StringCalculator.add("10")).to eql(10)
end
end
end
end
実行してみましょう。
1つ目のRSpecで期待する値(expected)は4に対して、受け取った結果の値(got)は0だよ、2つ目のRSpecでは期待する値(expected)は10に対して、受け取った結果の値(got)は0だよって書かれています。ゴールはRSpecを通すことなので、RSpecの対象となっているクラス(ここではStringCalculatorクラス)を修正します。
class StringCalculator
def self.add(input)
if input.empty?
0
else
input.to_i
end
end
end
RSpecを実行してみてください。下記のようになると無事RSpecが通りました。
複数の数字でメソッドを試してみる
最後に複数の文字列数字をカンマ区切りで渡した場合(本来のメソッド処理)のケースを試します。
require "string_calculator"
describe StringCalculator do
describe ".add" do
context "two numbers" do
context "given '3,5'" do
it "returns 8" do
expect(StringCalculator.add("3,5")).to eql(8)
end
end
context "given '1000,200'" do
it "returns 1200" do
expect(StringCalculator.add("1000,200")).to eql(1200)
end
end
end
end
end
ここで再度StringCalculatorをクラスを修正します。
class StringCalculator
def self.add(input)
if input.empty?
0
else
numbers = input.split(",").map { |num| num.to_i }
numbers.inject(0) { |sum, number| sum + number }
end
end
end
RSpecを実行します。
##おまけ
RSpecはアウトプットの表示方法がいくつかあって、そのうちのひとつにdocumentationフォーマットがあります。やり方は簡単で、
bundle exec rspec --format documentation
とするだけです。