狠狠撸

狠狠撸Share a Scribd company logo
First Step TDD
2012/7/27 yoyogi.rb
罢顿顿と开発环境
自己紹介


curl http://cui-about.me/nysalor
今回あまり準備していません(ごめんなさい)
TDD?


テスト駆動開発

テストを書いてからコードを書く
手顺
手顺
 Red   失败するテストを书く
手顺
 Red     失败するテストを书く

 Green   成功するコードを書く
手顺
   Red      失败するテストを书く

  Green     成功するコードを書く

 Refactor    リファクタリング
Why TDD?

常に整合性を保ってプログラミングできる

いつでもリファクタリングできる

要件や仕様の不明点がはっきりする

自信と安心を与えてくれる(重要)
Rspec


テスティングフレームワーク

Railsでよく使われるが、Ruby全般で利用可能

視覚的に分かりやすい
インストール



gem install rspec
何を作るか?


誕生日と現在の日付から年齢を計算するクラス

AgeCalc
とりあえず书いてみる
とりあえず书いてみる

[age_calc_spec.rb]
require './age_calc'
とりあえず书いてみる

[age_calc_spec.rb]
require './age_calc'




[age_calc.rb]
class AgeCalc
end
とりあえず书いてみる
                       テストコード


[age_calc_spec.rb]
require './age_calc'




[age_calc.rb]
class AgeCalc
end
とりあえず书いてみる
                       テストコード


[age_calc_spec.rb]
require './age_calc'



                       プロダクトコード

[age_calc.rb]
class AgeCalc
end
テスト実行
テスト実行
% rspec -cfs --color age_calc_spec.rb
No examples found.

Finished in 0.00005 seconds
0 examples, 0 failures
事前準备
事前準备

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  before do
    @age_calc = AgeCalc.new
  end
end
事前準备
                              テストコード



[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  before do
    @age_calc = AgeCalc.new
  end
end
最初のテスト
最初のテスト
[age_calc_spec.rb]
require './age_calc'
require 'date'
describe AgeCalc do
  before do
    @age_calc = AgeCalc.new
  end
  it "birthdayで誕生日が設定できること" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.birthday.should == Date.new(1989,2,25)
  end
end
最初のテスト
                                            テストコード
[age_calc_spec.rb]
require './age_calc'
require 'date'
describe AgeCalc do
  before do
    @age_calc = AgeCalc.new
  end
  it "birthdayで誕生日が設定できること" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.birthday.should == Date.new(1989,2,25)
  end
end
Red!
Red!
% rspec -cfs --color age_calc_spec.rb
AgeCalc
  birthdayで誕生日が設定できること (FAILED - 1)
Failures:
  1) AgeCalc birthdayで誕生日が設定できること
     Failure/Error: @age_calc.birthday = Date.new(1989,2,25)
     NoMethodError:
       undefined method `birthday=' for #<AgeCalc:
0x007f8c02832e40>
     # ./age_calc_spec.rb:11:in `block (2 levels) in <top
(required)>'

Finished in 0.00045 seconds
1 example, 1 failure

Failed examples:

rspec ./age_calc_spec.rb:10 # AgeCalc birthdayで誕生日が設定できる
こと
実装
実装

#[age_calc.rb]
class AgeCalc
  def birthday=(date)
    @birthday = date
  end

  def birthday
    @birthday
  end
end
実装
                        プロダクトコード


#[age_calc.rb]
class AgeCalc
  def birthday=(date)
    @birthday = date
  end

  def birthday
    @birthday
  end
end
Green!
Green!


% rspec -cfs --color age_calc_spec.rb
AgeCalc
  birthdayで誕生日が設定できること

Finished in 0.00037 seconds
1 example, 0 failures
リファクタリング
リファクタリング


#[age_calc.rb]
class AgeCalc
  attr_accessor :birthday
end
リファクタリング
                            プロダクトコード




#[age_calc.rb]
class AgeCalc
  attr_accessor :birthday
end
Green!
Green!


% rspec -cfs --color age_calc_spec.rb
AgeCalc
  birthdayで誕生日が設定できること

Finished in 0.00037 seconds
1 example, 0 failures
テストケース追加
テストケース追加

[age_calc_spec.rb]
require './age_calc'
require 'date'
describe AgeCalc do
  ...
  it "ageで年齢が返ること" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.age.should == 23
  end
end
テストケース追加
                                               テストコード

[age_calc_spec.rb]
require './age_calc'
require 'date'
describe AgeCalc do
  ...
  it "ageで年齢が返ること" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.age.should == 23
  end
end
Red!
Red!
% rspec -cfs --color age_calc_spec.rb
AgeCalc
  birthdayで誕生日が設定できること (FAILED - 1)
Failures:
  1) AgeCalc ageで年齢が返ること
     Failure/Error: @age_calc.age.should == 23
     NoMethodError:
       undefined method `age' for #<AgeCalc:0x007fb8d28279d0>
     # ./age_calc_spec.rb:17:in `block (2 levels) in <top
(required)>'

Finished in 0.00045 seconds
2 example, 1 failure

Failed examples:

rspec ./age_calc_spec.rb:15 # AgeCalc ageで年齢が返ること
実装
実装

#[age_calc.rb]
class AgeCalc
  attr_accessor :birthday
  def age
    (Time.now.strftime("%Y%m%d").to_i -
      @birthday.strftime("%Y%m%d").to_i) / 10000
  end
end
実装
                                         プロダクトコード



#[age_calc.rb]
class AgeCalc
  attr_accessor :birthday
  def age
    (Time.now.strftime("%Y%m%d").to_i -
      @birthday.strftime("%Y%m%d").to_i) / 10000
  end
end
Green!
Green!



% rspec -cfs --color age_calc_spec.rb
#=> 省略
テストケース追加
テストケース追加
#[age_calc_spec.rb]
require './age_calc'
require 'date'
describe AgeCalc do

  ...
  it "birthdayが未設定の場合、ageでnilが返ること" do
    pending “あとで書く”
    @age_calc.age.should be_nil
  end
end
テストケース追加
                                   テストコード
#[age_calc_spec.rb]
require './age_calc'
require 'date'
describe AgeCalc do

  ...
  it "birthdayが未設定の場合、ageでnilが返ること" do
    pending “あとで書く”
    @age_calc.age.should be_nil
  end
end
Red!
Red!



% rspec -cfs --color age_calc_spec.rb
#=> 省略
実装
実装
[age_calc.rb]
class AgeCalc
...
  def age
    if @birthday
      (Time.now.strftime("%Y%m%d").to_i -
        @birthday.strftime("%Y%m%d").to_i) / 10000
    else
      nil
    end
  end
end
実装
                                         プロダクトコード
[age_calc.rb]
class AgeCalc
...
  def age
    if @birthday
      (Time.now.strftime("%Y%m%d").to_i -
        @birthday.strftime("%Y%m%d").to_i) / 10000
    else
      nil
    end
  end
end
Green!
Green!



% rspec -cfs --color age_calc_spec.rb
#=> 省略
その他の惭补迟肠丑别谤
raise_error
raise_error

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "birthdayにDate以外の値を設定すると、ageで例外が返る
こと" do
    @age_calc.birthday = “23 years ago”
    lambda{@age_calc.age}.should raise_error
  end
end
raise_error
                                               テストコード

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "birthdayにDate以外の値を設定すると、ageで例外が返る
こと" do
    @age_calc.birthday = “23 years ago”
    lambda{@age_calc.age}.should raise_error
  end
end
change
change

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "increment_ageでageが1増えること" do
    @age_calc.birthday = Date.new(1989,2,25)
    lambda {@age_calc.increment_age}.should
change(@age_calc.age).from(23).to(24)
  end
end
change
                                               テストコード

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "increment_ageでageが1増えること" do
    @age_calc.birthday = Date.new(1989,2,25)
    lambda {@age_calc.increment_age}.should
change(@age_calc.age).from(23).to(24)
  end
end
be_close
be_close

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "ageが20から30の間にあること" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.age.should be_close(20,30)
  end
end
be_close
                                               テストコード


[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "ageが20から30の間にあること" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.age.should be_close(20,30)
  end
end
be_xxxx
be_xxxx

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "yearsが空になること" do
    @age_calc.years.should be_empty
  end
end
be_xxxx
                                      テストコード


[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "yearsが空になること" do
    @age_calc.years.should be_empty
  end
end
否定
否定

[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "ageがDateクラスのオブジェクトでないこと" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.age.should_not be_is_a(Date)
  end
end
否定
                                               テストコード


[age_calc_spec.rb]
require './age_calc'
describe AgeCalc do
  ...
  it "ageがDateクラスのオブジェクトでないこと" do
    @age_calc.birthday = Date.new(1989,2,25)
    @age_calc.age.should_not be_is_a(Date)
  end
end
以下余谈(时间があれば)
开発环境
rvm/rbenv
rvm/rbenv
RVM http://beginrescueend.com/
rvm/rbenv
RVM http://beginrescueend.com/

rbenv https://github.com/sstephenson/rbenv
rvm/rbenv
RVM http://beginrescueend.com/

rbenv https://github.com/sstephenson/rbenv

 複数バージョンのRubyを同居

 「前のバージョン用のgemを使ってしまった」を防ぐ

 開発?運用環境で同じRubyを使うメリット
rvm/rbenv
RVM http://beginrescueend.com/

rbenv https://github.com/sstephenson/rbenv
rvm/rbenv
RVM http://beginrescueend.com/

rbenv https://github.com/sstephenson/rbenv
rvm/rbenv
RVM http://beginrescueend.com/

rbenv https://github.com/sstephenson/rbenv

 RVMが主流→最近はrbenvが流行

 RVMは多機能だけど何度かやらかした

 rbenvは実行ファイルにやや癖がある?
screen/tmux
screen/tmux
screen/tmux
screen/tmux
screen/tmux
ターミナルマルチプレクサ

irb,logなど複数のシェルを行き来するのに便利

落ちても再起動するまでセッションが消えない

設定がけっこう大変

tmuxinator/screeninator
git
git
 分散リポジトリ

 学習コストが高い?

 svnに慣れすぎていなければ平気

 githubやherokuでどっちみち必要

 GUIクライアント?
sourcetree
sourcetree
http://www.sourcetreeapp.com/
sourcetree
http://www.sourcetreeapp.com/
sourcetree
http://www.sourcetreeapp.com/




                          見やすい
                          多機能(っぽいけどあまり使ってない)
                          登録必要だけど無料
gitx
gitx
       http://gitx.frim.nl/
gitx
       http://gitx.frim.nl/
gitx
       http://gitx.frim.nl/




                              軽い
                              機能少ない
                              diff見るだけなら十分
github
github
   http://github.com/
github
   http://github.com/
github
   http://github.com/




                        githubでいいんじゃね?
                        プライベートリポジトリは有料
                        ネットがないと使えない
tig
tig
  https://github.com/jonas/tig
tig
  https://github.com/jonas/tig




                             意外に見やすい
                             おすすめ
やっぱり颁鲍滨
やっぱり颁鲍滨

GUIはdiff見たり検索するだけ

どっちみちCUIの操作は必要

苦手な人は覚えましょう

git log --graph
Emacs
Emacs


Cocoa Emacs(自分でビルド)

inline-patch
full screen
Emacs
Emacs

ruby-mode
ruby-electric
rinari
etags
auto-complete
Emacs
Emacs
Emacs
Emacs
Emacs


設定をDropboxに置く

起動したらずっとそのまま

export EDITOR=emacsclient
Pow
Pow
      http://pow.cx/
Pow
      http://pow.cx/
Pow
      http://pow.cx/
Pow
      http://pow.cx/
Pow
      http://pow.cx/

いちいちrails serverしなくてもいい

http://xxxx.devでアクセスできる

複数プロジェクトの同時開発に対応

最近LAN内の別の端末から見れるようになった
Pow
      http://pow.cx/
Pow
      http://pow.cx/
Pow
        http://pow.cx/


gem install powder
powder -rでサーバ再起動

powder applog,powder linkなど
guard
guard
https://github.com/guard/guard
guard
https://github.com/guard/guard

TDD
ファイルが更新されると自動実行

いちいちrspecを実行するとサボりがち

coffee scriptの開発などにも使える

autospecというのもある
spork
spork
https://github.com/sporkrb/spork
spork
https://github.com/sporkrb/spork



分散テスト

同時に複数のテストが実行される

データベースを初期化する仕組みが不可欠
质疑応答
质疑応答

if available?
??Question.all.map(&:answer!)
end
gist

 https://gist.github.com/
 3187454 (test)
 https://gist.github.com/
 3187465 (production)

More Related Content

First Step TDD

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n