RSpec

WEB+DB PRESS vol.61 の特集記事を見つつ色々ヤッてみます。とりあえず環境の確認から。

$ ruby -v
ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]
$ gem -v
1.8.8
$ rails -v
Rails 3.0.9
$

とりあえず sqlite3 を入れます。

$ sudo apt-get install sqlite3

で、rails のアプリを作るのか。
以下らしい。

$ rails new webpress61_blog -T

出力多いですな。ちなみに -T は Test::Unit なナニを組込まないオプションとのこと。次に Gemfile に以下を追加とのこと。

group :development, :test do
  gem "rspec", "2.4.0"
  gem "rspec-rails", "2.4.1"
end

で、bundle install すれば良いらしい。便利な世の中になったものです。

$ bundle install
Fetching source index for http://rubygems.org/
Using rake (0.9.2) 
Using abstract (1.0.0) 
Using activesupport (3.0.9) 
Using builder (2.1.2) 
Using i18n (0.5.0) 
Using activemodel (3.0.9) 
Using erubis (2.6.6) 
Using rack (1.2.3) 
Using rack-mount (0.6.14) 
Using rack-test (0.5.7) 
Using tzinfo (0.3.29) 
Using actionpack (3.0.9) 
Using mime-types (1.16) 
Using polyglot (0.3.2) 
Using treetop (1.4.10) 
Using mail (2.2.19) 
Using actionmailer (3.0.9) 
Using arel (2.0.10) 
Using activerecord (3.0.9) 
Using activeresource (3.0.9) 
Using bundler (1.0.15) 
Installing diff-lcs (1.1.3) 
Installing rdoc (3.9.4) 
Using thor (0.14.6) 
Using railties (3.0.9) 
Using rails (3.0.9) 
Installing rspec-core (2.4.0) 
Installing rspec-expectations (2.4.0) 
Installing rspec-mocks (2.4.0) 
Installing rspec (2.4.0) 
Installing rspec-rails (2.4.1) 
Using sqlite3 (1.3.4) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
$

で、以下なおまじないを最初の一発めに、ということらしい。

$ rails generate rspec:install
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
$

とりあえず RSpec の第一歩の手前まできたのか。

モデルのテストを書いてみよう

まず、モデルを作成する模様。

$ rails generate model article title:string body:text
      invoke  active_record
      create    db/migrate/20110902125048_create_articles.rb
      create    app/models/article.rb
      invoke    rspec
      create      spec/models/article_spec.rb
$
||
む、spec 配下も自動生成な模様。で、db を作るのか。あまり何も考えてなかったのですが、config/database.yml は以下らしい。
>||
# SQLite version 3.x
#   gem install sqlite3
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000

production:
  adapter: sqlite3
  database: db/production.sqlite3
  pool: 5
  timeout: 5000

自動か。凄いな。とりあえず rake db:migrate せよ、との記述あり。

$ rake db:migrate
==  CreateArticles: migrating =================================================
-- create_table(:articles)
   -> 0.0028s
==  CreateArticles: migrated (0.0029s) ========================================

$

なんだか数年前の良い思い出がよみがえってくるようだ。とりあえず spec/models/articles_spec.rb を以下にせよ、とのこと。
ちょっと見栄を張って英語にしてたりして。

require 'spec_helper'

describe Article do
  context "case of specifying a title and body" do
    before do
      @article = Article.new(:title => "first blog",
                             :body => "This is first post."
                             )
    end
    it "Must be set title" do
      @article.title.should == "first blog"
    end
    it "Must be set body" do
      @article.body.should == "This is first post."
    end
  end
end

で、試験実行してみたら通らん。

$ bundle exec rspec spec/models/article_spec.rb
FF

Failures:

  1) Article case of specifying a title and body Must be set title
     Failure/Error: @article = Article.new(:title => "first blog",
     ActiveRecord::StatementInvalid:
       Could not find table 'articles'
     # ./spec/models/article_spec.rb:6:in `new'
     # ./spec/models/article_spec.rb:6:in `block (3 levels) in <top (required)>'

  2) Article case of specifying a title and body Must be set body
     Failure/Error: @article = Article.new(:title => "first blog",
     ActiveRecord::StatementInvalid:
       Could not find table 'articles'
     # ./spec/models/article_spec.rb:6:in `new'
     # ./spec/models/article_spec.rb:6:in `block (3 levels) in <top (required)>'

Finished in 0.09132 seconds
2 examples, 2 failures
$

テーブル無いし、とか出力されてるし。db/development.sqlite3 の中を見たら

sqlite> .schema
CREATE TABLE "articles" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "body" text, "created_at" datetime, "updated_at" datetime);
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
sqlite>

とのこと。これって RAILS_ENV だったかが微妙なのかな。しかも git で云々してないことに今更気づいておりますorz
で、色々探して以下を発見。

$ find |xargs grep RAILS_ENV
./spec/spec_helper.rb:ENV["RAILS_ENV"] ||= 'test'
$

変えましょうね。で、リトライ。

$ bundle exec rspec spec/models/article_spec.rb
..

Finished in 0.19687 seconds
2 examples, 0 failures
$

やれやれ。あるいは出力が以下で変わるらしい。

$ bundle exec rspec spec/models/article_spec.rb -f d

Article
  case of specifying a title and body
    Must be set title
    Must be set body

Finished in 0.35993 seconds
2 examples, 0 failures
$ 

次、validation の試験を書くらしい。title 属性が必須項目である試験は以下とのこと。

  context "case of not specifying a title" do
    before do
      @article = Article.new
    end
    it { @article.should_not be_valid }
  end

これは失敗しますな。

$ bundle exec rspec spec/models/article_spec.rb -f d

Article
  case of specifying a title and body
    Must be set title
    Must be set body
  case of not specifying a title
    should not be valid (FAILED - 1)

Failures:

  1) Article case of not specifying a title 
     Failure/Error: it { @article.should_not be_valid }
       expected valid? to return false, got true
     # ./spec/models/article_spec.rb:21:in `block (3 levels) in <top (required)>'

Finished in 0.28405 seconds
3 examples, 1 failure
$

あるいは必須項目な確認の記述があります。こうしたら title 属性が必須になるらしい。app/models/article.rb です。

class Article < ActiveRecord::Base
  validates_presence_of :title
end

これで再度試験をしてみます。

$ bundle exec rspec spec/models/article_spec.rb -f d

Article
  case of specifying a title and body
    Must be set title
    Must be set body
  case of not specifying a title
    should not be valid

Finished in 0.29035 seconds
3 examples, 0 failures
$

をー、通りましたな。
で、最後の正常系の試験を追加するらしい。

  context "case of specifying a title" do
    before do
      @article = Article.new(:title => "first blog")
    end
    it { @article.should be_valid }
  end

なんか格好良いですね。試験実行。

$ bundle exec rspec spec/models/article_spec.rb -f d

Article
  case of specifying a title and body
    Must be set title
    Must be set body
  case of not specifying a title
    should not be valid
  case of specifying a title
    should be valid

Finished in 0.14967 seconds
4 examples, 0 failures
$

試験ドリブン大好きです。英語は間違ってるはずですが気持ち良い。
続きは明日の朝にします。