Rails で文献管理システムを作ってみるよ(2/n)
前回はこちら.
- 本日のお品書き
- test の作成, 修正, 追加
- Article 作成時の修正
- (start|end)_page は integer で渡す. model でそれをチェックする.
- year は Date オブジェクトを渡す. 必要なのは year のみ.
の予定でしたが,方針を変えて, 勉強がてら RSpec on Rails を使用してみます.前回, 既に scaffold を使って model, view, controller を作成しているのですが, これを一度忘れてみましょう(なんてこった).
$ ruby script destroy scaffold Article
さよ〜なら〜
RSpec on Rails の導入
ついでに, Selenium on Rails も導入しておきます.
$ rake db:create $ ruby script/plugin install http://rspec.rubyforge.org/svn/tags/CURRENT/rspec $ ruby script/plugin install http://rspec.rubyforge.org/svn/tags/CURRENT/rspec_on_rails $ ruby script/plugin install http://svn.coderepos.org/share/lang/ruby/selenium_rc_spec
RSpec の準備
$ ruby script/generate rspec
Article モデルの作成
まずは rspec_model を作成します.
$ ruby script/generate rspec_model Article \ title:string \ authors:string \ year:datetime \ journal:string \ volume:integer \ start_page:integer \ end_page:integer ... $ rake db:migrate $ rake db:text:clone # Spec 用データベースを生成
というわけで, 以後は
(1) Spec で振る舞いを記述
(1) テスト(赤)
(1) コードの実装
(1) テスト(緑)
(1) リファクタリング
の順に開発を行なっていきます.
振る舞いの記述
spec/model/article_spec.rb で Spec を記述します. 何も記述していないと,
require File.dirname(__FILE__) + '/../spec_helper' describe Article do before(:each) do @article = Article.new end it "should be valid" do @article.should be_valid end end
となっていると思いますので, これを修正します.
例えば「タイトルが空の場合は Article を記述できない」という Spec を記述するならば
require File.dirname(__FILE__) + '/../spec_helper' describe Article," を生成するとき" do before(:each) do @title = 'タイトルの例' @authors = '著者の例' @year = '2004' # 年の例 @journal = '雑誌の例' @volume = '雑誌の巻数の例' @start_page = '001' # start page の例 @end_page = '020' # end page の例 end it "は, title が空の場合 valid ではないこと" do @article = Article.new( :title => nil, :authors => @authors, :year=> @year, :journal => @journal, :volume => @volume, :start_page => @start_page, :end_page => @end_page) @article.should_not be_valid end end
といった感じですかね. ちなみに, ファイルは UTF-8 で作成しておきます. あと, config/environment.rb の冒頭に $KCODE='u' を追加しておきます.
テスト(赤)
ここで spec でテストを行なうと,
$ rake spec ... 1) 'Article を生成するとき は, title が空の場合 valid ではないこと' FAILED expected valid? to return false, got true ./spec/models/article_spec.rb:23: Finished in 0.339274 seconds 1 example, 1 failure rake aborted!
となって, app/model で実装していないので, テストは失敗します.
コードの実装
次に app/model/article.rb を実装します. 以下の様に.
class Article < ActiveRecord::Base validates_presence_of :title end
テスト(緑)
そして spec を実行すると
$ rake spec ... . Finished in 0.339777 seconds 1 example, 0 failures
となります. spec に記述した振舞い通りに model が動いていることが test された訳です.
最終的に
Article モデルはどうしたかったのか, と言えば,
- title, authors, year は必須.
- start_page と end_page は, start_page <= end_page とする.
でした.
そんな訳で, 書いた spec とモデルは以下の通り
require File.dirname(__FILE__) + '/../spec_helper' require 'date' describe Article," を生成するとき" do before(:each) do @title = 'タイトルの例' @authors = '著者の例' @year = Date.today @journal = '雑誌の例' @volume = '雑誌の巻数の例' @start_page = '001' # start page の例 @end_page = '020' # end page の例 end it "は, title が空の場合 valid ではないこと" do @article = Article.new( :title => nil, :authors => @authors, :year=> @year, :journal => @journal, :volume => @volume, :start_page => @start_page, :end_page => @end_page) @article.should_not be_valid end it "は, authors が空の場合 valid ではないこと" do @article = Article.new( :title => @title, :authors => nil, :year=> @year, :journal => @journal, :volume => @volume, :start_page => @start_page, :end_page => @end_page) @article.should_not be_valid end it "は, year が空の場合 valid ではないこと" do @article = Article.new( :title => @title, :authors => @authors, :year=> nil, :journal => @journal, :volume => @volume, :start_page => @start_page, :end_page => @end_page) @article.should_not be_valid end it "は, start_page < end_page でなければならないこと" do @article = Article.new( :title => @title, :authors => @authors, :year=> @year, :journal => @journal, :volume => @volume, :start_page => @end_page, :end_page => @start_page) @article.should_not be_valid end end
で, これをテスト(緑)にしたモデルが
class Article < ActiveRecord::Base require 'date' validates_presence_of :title, :authors, :year protected def validate if start_page > end_page errors.add :start_page, "始めのページが最後のページより大きいよ?" end end end
次は
- fixtures を使って, spec をもっと簡潔に書く
- controller, view も spec を使うよ
へ続きます. 多分.