昨日、渋谷の
Ruby勉強会、「Shibura.rb」に参加してきました。
いろいろと役に立つ発表が聞けたのですが、とくに @r7kamura さんのTest on
Railsの話が参考になりました。
この発表が起点となって、優れた
Rubyist達の
RSpecの書き方に関して議論が巻き起こってたのですが、
- Modelのテストはしっかり書く
- Controllerのテストはそんなに書かない
- before(:each) とか使わない
- subject使う
みたいなのがどうも流行りみたいで、全部自分がやってるのと真逆だなぁと痛感させられました。
Modelのコードはテスト/プロダクションともに少ない、Controllerのテストがっつり、before(:each)使いまくり、subject使ってない、でした(´・ω・`)
というわけでさっそく今日、subjectを使ってeachを使うのをやめてみるのにトライ。
名前が必須なTeamというModelのテストで、名前がnullだとエラーになることの検証をするのにこういうコードを書いてたのですが、
let(:team){Team.new}
before(:each) do
team.name = nil
end
it "should_not be_valid" do
team.should_not be_valid
end
これはこんな感じで書けますね。(※この記事内のテストコードはdescribeとかcontextは省略してます)
subject{Team.new}
it{should_not be_valid}
とはいえ、上のコードは明示的にnameにnilを入れていますが下のコードはnilを入れていないのでやっていることが違いますね。
このTeamは生成したときにnameがnilになるので下の書き方でもテストが通るのですが、明示的にnilを入れたい場合どうすればいいのかなぁ、というのが悩み。
subject{
team = Team.new
team.name = nil
}
it{should_not be_valid}
こう書いた場合、subjectは{}内の戻り値を値に取るので、この場合だとteam.name = nilの戻り値、nilになってしまってitが対象にするのがTeamの
インスタンスではなくなりテストが通らなくなるんですよね。これを防ごうとすると、
subject{
team = Team.new
team.name = nil
team
}
it{should_not be_valid}
という書き方であれば通りますが、なんかこれだとbefore(:each)使うパターンと行数が変わらないので他にいい方法があるのかな、というのが気になっているところ。
他にも、teamは必須項目として同じくowner_idを持つとした場合、エラーがowner_idが空であることに起因せず、nameが空なのでエラーであることを検証しようとすると、before(:each)を使うなら以下の様な書き方になると思います。
let(:team){Team.new}
before(:each) do
team.name = nil
team.owner_id = 1
end
it "should_not be_valid" do
team.should_not be_valid
end
これをsubjectを使うのであれば
subject{
team = Team.new
team.name = nil
team.owner_id = 1
team
}
it{should_not be_valid}
letも組み合わせるなら
let(:team){
team = Team.new
team.name = nil
team.owner_id = 1
team
}
subject{team}
it{should_not be_valid}
みたいな書き方になるのかな、と思いました。
で、一番最後の
インスタンス返すために team だけの行がイマイチなのとそもそもbefore(:each)の場合と可読性/行数共にあまり変わらない気がしたので、他の人達はどういう書き方をしているのかな、というのが今すごく気になっているところだったりします。