testで似た処理をまとめよう
最近railsで開発している時に、TDDにもちょっとづつ慣れてきたつもりになっていますが、テストを書いている時、同じような処理をコピペでごまかしている自分がいました。
DRYに反する自分。でも、どうにもできない自分。
「これじゃいかん!」と言うことで休日を利用してチャレンジしました。
やりたい事
-
- 各属性title,content,authorともに、nilだとvalidではじかれる事を、テストで確認できるようにしたい。
今までのテスト
def setup @hoge = Hoge.new end def test_valid_failure_nil_title @hoge.title = nil @hoge.content = "fuga" @hoge.author = "piyo" assert_equal false, @hoge.valid? end def test_valid_failure_nil_content @hoge.title = "fuga" @hoge.content = nil @hoge.author = "piyo" assert_equal false, @hoge.valid? end def test_valid_failure_nil_author @hoge.title = "fuga" @hoge.content = "piyo" @hoge.author = nil assert_equal false, @hoge.valid? end
んー、似てることやってるのに凄く効率が悪い…
と言うことで、改造してみました。
結果
def create_default_description(substitute_value) @hoge = Hoge.new description = {"title" => "hoge", … (1) "content" => "fuga", "author" => "piyo" } description.update(substitute_value) … (3) description.each do |key,value| eval("@hoge.#{key} = value") end end def test_create_failure_nil_title substitute_value = {"title" => nil} … (2) create_default_description(substitute_value) assert_equal false, @hoge.valid? end def test_create_failure_nil_content (省略)
と言う感じです。
一般化したメソッドに、どうやって、title,content,authorに
違う値をいれれば良いのか悩んでしまったのですが、
(1) 一般化したメソッド内に、description というHashに、初期値を用意してあげておく。
(2) テストしたい属性もHashにいれてあげて、引数として渡す。
(3) updateメソッドを使ってあげる事で、初期値と引数の差分の所だけ更新してもらう。
と言うことで解決できることが分かりました。
リファレンスマニュアルさまさまです!!
これなら、属性の数が増えても、そして、nil以外の色々な値を試したくなっても大丈夫そう。かな?
しかし、衝撃の事実。ソースが長くなっている…
そもそも、全てのケースを試さないで大丈夫なような、効率の良いテストをしっかり考えられるように、勉強しなければなぁと思った一日でした。
以下は、実際に挙動を確かめるためのソースです。
class Hoge attr_accessor :title, :content, :author def initialize @title @content @author end end def create_default_description(s_v) @hoge = Hoge.new description = {"title" => "hoge", "content" => "fuga", "author" => "piyo" } description.update(s_v) description.each do |key,value| eval("hoge.#{key} = value") end p hoge #=> #<Content:0x2b5582c @author="piyo", @content="fuga", @title=nil> end substitute_value = {"title" => nil} create_default_description(substitute_value)