15. そして実装を書く
def gcm(a, b) !
4!
end !
おい! ちゃんと計算しろ!
でもテストは通るからOK
describe 'gcm' do !
it 'should return 4 that gcm(12, 28)' do !
expect(gcm(12, 28)).to eq 4 !
end !
end
15
16. さらにテストを書く
describe 'gcm' do !
it 'should return 4 that gcm(12, 28)' do !
expect(gcm(12, 28)).to eq 4 !
end !
it 'should return 7 that gcm(21, 28)' do !
expect(gcm(21, 28)).to eq 7 !
end !
end!
基本的なケース2: 21と28なら7
16
17. 実装を修正する
def gcm(a, b) !
a == 12 ? 4 : 7
end !
おい! ちゃんと計算しろって!!!
でもテストは通るからOK
describe 'gcm' do !
it 'should return 4 that gcm(12, 28)' do !
expect(gcm(12, 28)).to eq 4 !
end !
it 'should return 7 that gcm(21, 28)' do !
expect(gcm(21, 28)).to eq 7 !
end !
end!
17
18. よろしい、ならば戦争だ
describe 'gcm' do !
it 'should return 4 that gcm(12, 28)' do !
expect(gcm(12, 28)).to eq 4 !
end !
it 'should return 7 that gcm(21, 28)' do !
expect(gcm(21, 28)).to eq 7 !
end !
it 'should return 7 that gcm(28, 21)' do !
大小入れ替え
expect(gcm(28, 21)).to eq 7 !
end !
it 'should return 28 that gcm(28, 28)' do ! 同じ数
expect(gcm(28, 28)).to eq 28 !
end !
it 'should raise error that gcm(-1, 6)' do !
変な値→例外来い
expect{gcm(-1, 6)}.to raise_error !
end !
end!
18
19. そろそろ真面目に実装する
def gcm(a, b) !
raise ArgumentError.new if a < 1 || b < 1 !
if a < b !
gcm(b, a)
else !
if a % b == 0 !
b
else !
gcm(b, a % b)
end !
end !
end !
※テストに通りました
19
28. RSpecの雰囲気
describe Array, "when empty" do !
何についてテストするのかを書ける
before do !
@empty_array = [] !
end !
before
に各テスト実行前の共通処理
it "should be empty" do !
@empty_array.should be_empty !
テスト内容をより明確に書ける
end !
テスト条件の記述が読み易い
it "should size 0" do !
@empty_array.size.should == 0 !
end !
after do !
@empty_array = nil !
aberに各テスト実行後の共通処理
end !
end!
28
29. RSpecは内容を仕様書的に出力できる
describe Array, "when empty" do !
before do !
@empty_array = [] !
end !
it "should be empty" do !
@empty_array.should be_empty !
end !
it "should size 0" do !
@empty_array.size.should == 0 !
こんな感じ
%
spec
-‐fs
array_spec.rb
Array
when
empty
-‐
should
be
empty
-‐
should
size
0
end !
after do !
@empty_array = nil !
end !
end!
29
47. Stubで振る舞いを変える
Time
に
now
が来たら特定の値を返すように仕込む
describe 'is_sunday?' do !
it 'should be true if today is Sunday' do !
# 2014/2/2 は 日曜日
Time.stub(:now).and_return(Time.new(2014, 2, 2)) !
expect(is_sunday?).to eq true !
end !
it 'should be false if today is Saturday' do !
# 2014/2/1 は 土曜日
Time.stub(:now).and_return(Time.new(2014, 2, 1)) !
expect(is_sunday?).to eq false !
end !
end!
47
55. とりあえずテスト書いて実行
describe SomeClass do !
※中身がない
describe 'print_prefecture' do !
it 'should print 東京都 when zipcode=1030000' !
it 'should not print anything when zipcode=1030900' !
end !
end !
SomeClass
print_prefecture
should
print
東京都 when
zipcode=1030000
(PENDING:
Not
yet
implemented)
should
not
print
anything
when
zipcode=1030900
(PENDING:
Not
yet
implemented)
Finished
in
0.00034
seconds
2
examples,
0
failures,
2
pending
「Pending」になる。これもSpec系の特徴。
「失敗」とは少し違う。「まだ書いてないよ」という状態。
55
57. とりあえずこんな感じで
class SomeClass !
def print_prefecture(zipcode) !
prefecture = get_prefecture(zipcode) !
ここで都道府県が戻る想定
!
if prefecture !
puts prefecture !
end !
end !
end !
Nil
じゃなければ出力
57
58. Stubでホワイトボックステスト
describe SomeClass do !
describe 'print_prefecture' do !
before do !
@obj = SomeClass.new !
@obj
に毎回Objectを入れる共通処理
end !
it 'should print 東京都 when zipcode=1030000' do !
@obj.stub(:get_prefecture => '東京都')
get_prefecture
が 東京都
end !
end !
end!
を返すならば
あれ?
Puts
したかってどうテストする?
出力したか、という判定をするのが難しい。
→
少し工夫が必要
※Kernel.puts
を調べれば良いんですけどね。今回はこういう想定で。
58
59. 実装コードをテストしやすく修正
class SomeClass !
def print_prefecture(zipcode) !
prefecture = get_prefecture(zipcode) !
if prefecture !
output(prefecture)
end !
end !
!
出力する、というのを呼び出すようにする
def output(str) !
puts str !
end !
end !
59
60. Output()をCallすればOKと考える
it 'should print 東京都 when zipcode=1030000' do !
get_prefecture
が 東京都 を返すなら
@obj.stub(:get_prefecture => '東京都')
@objは
output(‘東京都’)
が呼ばれることが期待される
expect(@obj).to receive(:output).with('東京都') !
じゃあ、実行しましょう
@obj.print_prefecture('1030000') !
end !
となる
60
61. Outputされないケースも追加
describe SomeClass do !
describe 'print_prefecture' do !
before do !
@obj = SomeClass.new !
end !
it 'should print 東京都 when zipcode is in 東京都 area' do !
@obj.stub(:get_prefecture => '東京都')
expect(@obj).to receive(:output).with('東京都') !
@obj.print_prefecture('1030000') !
end !
it 'should not print anything when zipcode doesnot exist' do !
Exampleの文言も修正する
nil) !
expect(@obj).not_to receive(:output)
@obj.stub(:get_prefecture =>
@obj.print_prefecture('1030900') !
end !
end !
end !
!
get_prefectureがnilの時も追加する
仮に:get_prefecture
が
nil
期待:
output()は呼ばれない
61
62. テスト実行!
SomeClass
print_prefecture
should
print
東京都 when
zipcode
is
in
東京都 area
should
not
print
anything
when
zipcode
doesnot
exist
Finished
in
0.00124
seconds
2
examples,
0
failures
テストが通った
62
63. 続けて細かい実装を先に書いてしまう
勢いってものがあるじゃないですか
require 'net/http' !
require 'rexml/document' !
class SomeClass !
def print_prefecture(zipcode) !
prefecture = get_prefecture(zipcode) !
if prefecture !
output(prefecture) !
end !
end !
def get_prefecture(zipcode) !
xml_data = Net::HTTP.get(URI.parse("http://zip.cgis.biz/xml/zip.php?zn=#{zipcode}")) !
scan_prefecture(xml_data) !
end !
def scan_prefecture(xml_data) !
attr_state = REXML::Document.new(xml_data).elements['//@state'] !
attr_state ? attr_state.value : nil !
end !
def output(str) !
puts str !
end !
end !
63
get_prefecture()
と
scan_prefecture()
に分けた
64. テスト: get_prefecture()
実装コード
def get_prefecture(zipcode) !
xml_data = Net::HTTP.get(URI.parse("http://zip.cgis.biz/xml/zip.php?zn=#{zipcode}")) !
scan_prefecture(xml_data) !
end !
テストコード
describe 'get_prefecture' do !
it 'should call API Request with zipcode' do !
expect(Net::HTTP).to receive(:get) !
expect(URI).to receive(:parse).with(/zn=1030000/) !
@obj.get_prefecture('1030000') !
end !
!
it 'should return scan_prefecture result' do !
Net::HTTP.stub(:get => 'SOME DATA') !
期待:HTTP.get
が呼ばれる
期待:URI.parse
が呼ばれて、
引数は
/zn=103000/
の
正規表現とMatchするはず。
expect(@obj).to receive(:scan_prefecture).with('SOME DATA').and_return('RESULT') !
expect(@obj.get_prefecture('1030000')).to eq('RESULT') !
end !
end !
仮に: HTTP.get
が
‘SOME
DATA’を返すとして、
期待:
@obj.scan_prefecture(‘SOME
DATA’)が呼ばれる
その結果が
‘RESULT’
だったとして、
期待:
@obj.get_prefecture()
の返り値は
’RESULT’
になる。
64
65. テスト: scan_prefecture()
実装コード
def scan_prefecture(xml_data) !
attr_state = REXML::Document.new(xml_data).elements['//@state'] !
attr_state ? attr_state.value : nil !
end !
テストコード
describe 'scan_prefecture' do !
it 'should return 東京都 if the xml data is so' do !
expect(@obj.scan_prefecture(D1)).to eq '東京都'
end !
!
期待:
scan_pefecture(sample1)な
ら戻り値は 東京都 である
!
it 'should return nil if the xml data doesnot contain pref info' do !
expect(@obj.scan_prefecture(D2)).to eq nil !
end !
end !
期待:
scan_pefecture(sample2)な
ら戻り値は
nil
である
65
※ブラックボックスになっている
66. describe SomeClass do !
before do !
@obj = SomeClass.new !
end !
describe 'print_prefecture' do !
it 'should print 東京都 when zipcode is in 東京都 area' do !
@obj.stub(:get_prefecture => '東京都')
expect(@obj).to receive(:output).with('東京都') !
@obj.print_prefecture('1030000') !
end !
it 'should not print anything when zipcode doesnot exist' do !
@obj.stub(:get_prefecture => nil) !
expect(@obj).not_to receive(:output) !
@obj.print_prefecture('1030900') !
end !
end !
describe 'get_prefecture' do !
it 'should call API Request with zipcode' do !
expect(Net::HTTP).to receive(:get) !
expect(URI).to receive(:parse).with(/zn=1030000/) !
@obj.get_prefecture('1030000') !
end !
it 'should return scan_prefecture result' do !
Net::HTTP.stub(:get => 'SOME DATA') !
expect(@obj).to receive(:scan_prefecture).with('SOME DATA').and_return('RESULT') !
expect(@obj.get_prefecture('1030000')).to eq('RESULT') !
end !
end !
describe 'scan_prefecture' do !
it 'should return 東京都 if the xml data is so' do !
expect(@obj.scan_prefecture(D1)).to eq '東京都'
end !
it 'should return nil if the xml data doesnot contain pref info' do !
expect(@obj.scan_prefecture(D2)).to eq nil !
end !
end !
end !
テスト全体
66
67. テスト実行
SomeClass
print_prefecture
should
print
東京都 when
zipcode
is
in
東京都 area
should
not
print
anything
when
zipcode
doesnot
exist
get_prefecture
should
call
API
Request
with
zipcode
should
return
scan_prefecture
result
scan_prefecture
should
return
東京都 if
the
xml
data
is
so
should
return
nil
if
the
xml
data
doesnot
contain
pref
info
Finished
in
0.00804
seconds
6
examples,
0
failures
テストが通った
67