ラベル rspec の投稿を表示しています。 すべての投稿を表示
ラベル rspec の投稿を表示しています。 すべての投稿を表示

2011年10月6日木曜日

backbone.jsをrails3で実行できるようにするシェルスクリプト(rails3.1対応版)

何度も同じ事しているので貼っておきます(rails3.1対応版)。
capybara/capybara-webkit/headless対応や、capistrano、staging対応、sub uri対応等を追加しています。
./gen.sh アプリ名
で利用できます(ノーエラーハンドリング上等!)

$ cat gen.sh

2011年10月4日火曜日

rails3.1 with rspec-request , capybaraでcookieを取り扱うには

rails3.1とrspec-requestsをcapybaraで利用した際に、cookieの扱い方が分からなかったのでメモしておきます。
# app/controllers/foo_controller.rb
class FooController < ApplicationController
  def index
    puts cookies["key1"]
    cookies["key1"] = '2'
    cookies.permanent["key2"] = "3"
  end
end

# spec/requests/foo_spec.rb
describe "foo周辺の仕様" do
  def cookies
    Capybara.current_session.driver.browser.current_session.instance_variable_get(:@rack_mock_session).cookie_jar
  end

  it "foo/index" do
    cookies["key1"] = '1'
    visit "/foo/index"
    cookies["key1"].should == '2'
    cookies["key2"].should == '3'
  end
end
上記の検証の過程で、
  • cookiesのキー名は文字列でないといけない(シンボルだと上手くいかない)
  • cookiesメソッドを上書く必要があり
  • permanentでも同じように読める("key2")
という事が判明しました。

ちなみに各プロダクトは下記の組み合わせで確認しました。
rails-3.1.0
rspec-2.6.0
rspec-rails-2.6.1
capybara-1.0.1

2011年9月26日月曜日

capybaraをwebkitやseleniumとかで動かす場合の注意点と解決策

■概要


capybaraとwebkit(たぶんselenium)を利用する際は、capybara側がブラウザとやりとりする為のスレッドを立ち上げる為
RSpec.configure do |config|
  ...
  config.use_transactional_fixtures = false
end
してfixtureのトランザクション制御をあきらめる必要があります。これでは少し都合が悪いので、 DatabaseCleanerを利用して代用する等行う必要があります。

ところがrailsコアチームのjosevalim氏が解決策をぼそっとつぶやいてました。実際にやってみると上手く動くだけでなく実行速度がかなり改善されました。

■解決策


つぶやきで紹介されている方法は非常に簡単です。
spec_helper(test_helper.rb)で下記の用に追記しましょう。
RSpec.configure do |config|
  ...
  config.use_transactional_fixtures = true
end

# 下記追加
class ActiveRecord::Base
  mattr_accessor :shared_connection
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end
end

ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
でいつもどおり

$ bundle exec rake spec

して見ましょう。specの実行速度が改善したのでは無いでしょうか?

ね、簡単でしょう!

@josevalim氏に多謝!

2011年9月20日火曜日

spec実行時にdb:test:prepareを呼び出したくない。


■概要

(激しく既出感ありですが。。)何年もrailsやってますが、正しく理解できていなかった事の一つに

  rake spec(test)すると、処理の一環としてdb:test:prepareタスクを呼び出す

という挙動があります。
通常問題にならないのですが、db:test:prepareが、db/schema.rbの情報を元にデーターベースを作成する為、railsが認識できないような項目は抜けて落ちてしまいます。

  • 関数適用したインデックス
  • トリガーやファンクション
  • 別スキーマに作ったオブジェクト ...etc

なので

RAILS_ENV=test rake db:drop
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate

してからrake specする事を前提に、db:test:prepareを呼び出さずにspecを実行する方法を模索しました。

■案1 db:test:prepare自体を書き換える

参照先にそのまんまの解決策が書かれています。
Rakefileでtask削除用のメソッドを用意します(load_tasksの前に!)。
Rake::TaskManager.class_eval do
  def remove_task(task_name)
    @tasks.delete(task_name.to_s)
  end
end

lib/tasks/db/test.rakeとかを作って、実際にタスクを上書きします
Rake.application.remove_task 'db:test:prepare'

namespace :db do
  namespace :test do 
    task :prepare do |t|
      # rewrite the task to not do anything you don't want
    end
  end
end

参考 http://stackoverflow.com/questions/1097845/how-to-prevent-rake-test-to-call-task-dbtestprepare

■案2 自力でspecを実行する

db:test:prepareを壊すのは怖いので...という方にはこのやり方

lib/tasks/spec.rakeとかを作って
require 'rake'
require 'rspec/core/rake_task'

namespace :spec do
  RSpec::Core::RakeTask.new('no_prepare_db') do |t|
    t.pattern = ['spec/**/*_spec.rb']
  end
  namespace :no_prepare_db do
    %w(controllers helpers lib mailers models requests routing views).each do |dir|
      RSpec::Core::RakeTask.new(dir) do |t|
        t.pattern = ["spec/#{dir}/**/*_spec.rb"]
      end
    end
  end
end
で、rake spec:no_prepre_dbや、rake spec:no_prepare_db:modelsで、db:test:prepareを呼び出さずに実行できます。

参考 http://old.nabble.com/db%3Atest%3Aprepare-interfering-with-rake-spec-pattern-td31075510.html

2011年8月23日火曜日

capybara-webkitを動かす 2011/08/23時点版

■概要

こちらの素晴らしい記事では、capybara-webkitを利用して、headlessでjsが動く環境を紹介されています。

capybara-webkitのこれまでリリースされているバージョン(~0.5.0)では、capybara1.0.0系への依存が解決できない為、抗う方法をご紹介されています。が、0.6.0からは上手く依存関係を解決されるようになりました!

■手順

こちらと同様ですが、Xvfbとqtの当たらしいバージョン(qt47)をインストールしておきます。
qt47にする理由はphantomjsも動かしたいからです ^o^

$ sudo yum -y install firefox ★ seleniumで動かす必要があれば
$ sudo yum -y install xorg-x11-server-Xvfb xorg-x11-fonts*
$ sudo vim /etc/yum.repos.d/atrpms.repo

[atrpms]
name= CentOS-$releasever - ATrpms
baseurl=http://dl.atrpms.net/el$releasever-$basearch/atrpms/testing/
gpgcheck=1
gpgkey=http://ATrpms.net/RPM-GPG-KEY.atrpms
enabled=0

$ sudo rpm --import http://packages.atrpms.net/RPM-GPG-KEY.atrpms
$ sudo yum -y install sqlite --enablerepo=atrpms ★依存関係からインストールする必要がある?
$ sudo yum -y install qt47-devel qt47-webkit qt47-webkit-devel --enablerepo=atrpms
$ sudo ln -s /usr/bin/qmake-qt47 /usr/bin/qmake (コンパイル時に必要とされるので予め作成)

でrailsプロジェクト側で

$ vim Gemfile
group :development, :test do
  ...
  gem 'capybara', '1.0.1'
  gem 'capybara-webkit', '0.6.0'
  gem 'headless', '0.1.0'
  ...
end
$ bundle install
$ vim spec/spec_helper.rb
...
require "capybara/rails"
require "capybara/rspec"
...
RSpec.configure do |config|
...
end

Capybara.javascript_driver = :webkit
$ vim spec/support/headless.rb
if %w(yes y on).include?(ENV['HEADLESS'])
  require 'headless'

  headless = Headless.new
  headless.start

  at_exit do
    headless.destroy
  end
end
$ vim spec/requests/index_spec.rb
# coding: utf-8

require 'spec_helper'

describe "Index" do
  describe "GET /" do
    it "/index.html", :js => true do
      visit "/"
      click_link "About your application’s environment"
      page.should have_content("No route matches")
    end
  end
end

$ HEADLESS=on bundle exec rspec spec/requests/index_spec.rb
Index
  GET /
    /index.html

Finished in 4.48 seconds
1 example, 0 failures
という訳でいい感じに実行できました~

2011年8月13日土曜日

ruby1.9時代にrcovは使ってはいけない。simplecovを使おう!

■概要

rubyにおけるテスト網羅率の定番ツールといえばrcovですが、どうもテストの通っている箇所の色付けがおかしいのと網羅率に誤差があると感じてました。

よくよくgithubのrcovのページを見てみると、

NOTE: This fork does not work on Ruby 1.9.x. For coverage on Ruby 1.9 look at SimpleCov. Even if you get results on 1.9 they will probably be inaccurate. Ruby 1.9 has call detection built in for faster, more accurate results.

なんて書いてあります。という訳でSimpleCovを試してみました。

なおこちらで簡単にセットアップできるシェルスクリプト置いてます!

■説明

まずはいつものGemfileに

gem 'simplecov', :require => false

と記載して

$ bundle install

次にspec/spec_helper.rbに下記コードを追加しましょう。
この時大事なのは実行の早い段階(railsが読み込まれる前!)で下記を実行する必要がある事です。

require 'simplecov'
SimpleCov.start 'rails'



$ rake spec

すると、coverageディレクトリ以下にhtmlファイルが出力されます(画像はsimplecovのページより)


このままでも良いのですが、rcovのフォーマットと異なるので、CIに統合するには不便です。そんな時はsimplecov_rcovを利用すると上手く行きます。

group :test do
  gem 'simplecov', :require => false
  gem 'simplecov-rcov', :require => false
end

$ bundle install

spec/spec_helper.rbには、SimpleCovの出力フォーマットを変更するコードを書きます。

require 'simplecov'
require 'simplecov-rcov'
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter

※くれぐれも早い段階で読み込んで下さい!

すると見慣れたあのHTMLがcoverage/rcov以下に出力されます。
coverage/rcovをCI(というかjenkins)のrcovレポートの場所として指定してあげると良好な結果が得られます!

ちなみにsimplecov-rcovのページで下記の様な記載があり、網羅率測定有無を切り替える方法があります。
if( ENV['COVERAGE'] == 'on' )
  require 'simplecov'
  require 'simplecov-rcov'
  SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
  ...
end

$ COVERAGE=on rake spec
また複数の出力フォーマットで出力する例もありますので是非見てみて下さい。

2011年1月26日水曜日

rails3とbackbone.jsの組み合わせで利用する2

■概要

前回に引き続き、backbone.jsを利用してjqueryでMVCの世界を、rails3と共に作っていこうと思います。
今回はデータのやり取りをする所までが目標です。

■モデル/コントローラ等を作成する

$ rails g scaffold post title:string body:text published:boolean
$ rake db:migrate
$ rake spec (とりあえずrspecが動くか確認しとく)
$ rake spec:rcov (ついでにrcovが動くか確認しとく)
$ rails s

ここで http://localhost:3000/posts でいつもの画面が表示されてればOK!

■json入出力用にコントローラを修正する

とりあえずjsonでやり取りできるように変更します。params.exceptはbackboneとのやり取りを考慮してます。

class PostsController < ApplicationController
  respond_to :json
  def index
    @posts = Post.all
    respond_with @posts
  end
  def show
    @post = Post.find(params[:id])
    respond_with @post
  end
  def create
    @post = Post.new(params.except(:action, :controller))
    respond_to do |format|
      if @post.save
        format.json { render :json => @post, :status => :created, :location => @post }
      else
        format.json { render :json => @post.errors, :status => :unprocessable_entity }
      end
    end
  end
  def update
    @post = Post.find(params[:id])
    respond_to do |format|
      if @post.update_attributes(params.except(:id, :action, :controller, :created_at, :updated_at))
        format.json { head :ok }
      else
        format.json { render :json => @post.errors, :status => :unprocessable_entity }
      end
    end
  end
  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    respond_to do |format|
      format.json { head :ok }
    end
  end
end

■jsonのフォーマットを変更する

このままだと下記の用に"post"が付いてしまうので、backbone側の期待と異なります。

http://localhost:3000/posts.json
=> [{"post":{"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}}]

http://localhost:3000/posts/1.json
=> {"post":{"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}}


config/initializers/include_root_in_json.rbの様なファイルを作成し

ActiveRecord::Base.include_root_in_json = false

とすると下記の様な感じでgoodです!

http://localhost:3000/posts.json
=> [{"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}]

http://localhost:3000/posts/1.json
=> {"body":"a","created_at":"2011-01-19T16:13:47Z","id":1,"published":false,"title":"aa","updated_at":"2011-01-19T16:13:47Z"}

■backbone用のcontorollerを作成

コントローラ/ビューを追加して必要な設定を追加します。

$ vim controllers/home_controller.rb

class HomeController < ApplicationController
  def index
  end
end

$ vim config/routes.rb
  root => "home#index"
$ rm public/index.html
$ mkdir views/home

■backbone.jsを使ってみる

$ vim views/home/index.html.erb



http://localhost:3000/ を開いて、画面に味気ないalertが表示されればOkay!!
railsのログとDB見てると少しは楽しいかも

次は画面を作っていきましょう!

2011年1月11日火曜日

rails3とbackbone.jsの組み合わせで利用する1

■概要
backendをrails3にして、backbone.jsを利用する為の手順を残しておきます。

■railsプロジェクトの作成
$ rails new demo -T -J -d mysql
demo プロジェクト名
-T testunitはいらない
-J prototype.jsはいらない
-d mysql データベースはmysql

■gemを追加
$ cd demo
$ vim Gemfile
下記を一番下に追加(本当はバージョンをつけた方が良い)
gem 'jquery-rails'
group :development, :test do
  gem 'rspec'
  gem 'rspec-rails'
  gem 'rcov'
end
$ bundle install

■コードジェネレート
$ rails g rspec:install
$ rails g jquery:install --ui

■まず使えるように編集
$ vim config/database.yml

$ vim app/views/layouts/application.html.erb
文字列エンコーディングを明確に指定する為に下記追加
<meta charset="utf-8"/>

$ vim config/application.rb
jquery-railsに、javascriptのdefaults設定はまかせる(コメントアウトする)
# config.action_view.javascript_expansions[:defaults] = %w()
これを有効にしたい

$ vim spec/spec_helper.rb

ruby1.9.2でrcovを正しく動作させる為に、下記を一番下に追加
# quick monkey patch for rcov
# http://codefluency.com/post/1023734493/a-bandaid-for-rcov-on-ruby-1-9
if defined?(Rcov)
  class Rcov::CodeCoverageAnalyzer
    def update_script_lines__
      if '1.9'.respond_to?(:force_encoding)
        SCRIPT_LINES__.each do |k,v|
          v.each { |src| src.force_encoding('utf-8') }
        end
      end
      @script_lines__ = @script_lines__.merge(SCRIPT_LINES__)
    end
  end
end

$ vim .rspec
spork等で動いてもいい様に下記を追加しておく
--drb

■backbone.jsの準備
$ cd public/javascripts
↓jsファイル取得。ここも本当はバージョンを明示すべきかな
$ wget http://documentcloud.github.com/underscore/underscore.js
$ wget http://documentcloud.github.com/underscore/underscore-min.js
$ wget http://documentcloud.github.com/backbone/backbone.js
$ wget http://documentcloud.github.com/backbone/backbone-min.js
$ cd ../..
$ vim app/views/layouts/application.html.erb
backbone.jsを読み込むようにする。下記をhead内に追加
<%= javascript_include_tag "underscore-min.js", "backbone-min.js" %>

■履歴管理開始
$ vim .gitignore (履歴管理しない最低限のものを追加)

.bundle
db/*.db
db/*.sqlite3
db/schema.rb
log/*.log
tmp/
coverage/
*.swp

$ git init
$ git add .
$ git commit -m "最初のコミット"

■DB作成
$ rake db:create:all
$ rake db:migrate

■起動
$ rails s

ここまでで準備完了!次は実際にデータの操作をしてみます

20110113 追記
http://d.hatena.ne.jp/nedate/20101004/1286183882を参考にrcovの設定も追加させてもらいました!

2011年1月4日火曜日

CoffeeScript面白そう2

前回インストールしてみたCoffeeScriptだが、jasmineと組み合わせるとこんな感じで、javascriptのspecが書けた。


describe "String クラスは", ->
  str = ""
  beforeEach ->
    str = "jasmine"
  it "split メソッドを持っている", ->
    expect(str.split).toBeDefined()
  describe "ネストは", ->
    it "当然いけます", ->
      expect(str).toEqual("jasmine")


オリジナルのjasmine specと比較して良いのは

  • {} とか () とか が激減している
  • functionって書かなくて良い
  • varも書かなくて良い

辺りでしょうか。本気で使うなら課題は

  • coffeeの実行(*.coffee -> *.jsにコンパイル)を自動化
  • expect ~ toEqualとかをもっと"rspec"らしくしたい
  • 上の"str"をrspecっぽく何とかしたい(無理かな?)

といった所かな。少し考えるか。。

2011/01/04 0:52 追記


変数にrubyっぽく@をつけて(thisとバインド)、上記は

describe "String クラスは", ->
  beforeEach ->
    @str = "jasmine"
  it "split メソッドを持っている", ->
    expect(@str.split).toBeDefined()

で動くんだ。