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

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年7月27日水曜日

coberturaが猛烈に遅い!...けど解決した

■概要

junitの網羅率測定する為に、coberturaを利用する事が多いと思います。

# 当方久しぶりにjavaを触ったので最近のトレンドにはとんと疎くなりました。もっと良いのがあれば教えてください。

しかしこれが猛烈に遅い!軽快に進めたいのですが、ネックになりそうなので調査しました。

■解説

coberturaの実行はantから行っています。通常

1. コンパイル
2. instrument (coberturaを埋め込む)
3. junit実行


の順番で実行する事になりますが、 3. が非常に遅いのです。

3. の実行は
<junit fork="yes" dir="${basedir}">
  <classpath location="${instrumented.dir}" />
  <classpath location="${classes.dir}" />
  <classpath refid="cobertura.classpath" />
  <formatter type="xml" />
  <test name="${testcase}" todir="${reports.xml.dir}" if="testcase" />
  <batchtest todir="${reports.xml.dir}" unless="testcase">
    <fileset dir="${src.dir}">
      <include name="**/*Test.java" />
    </fileset>
  </batchtest>
</junit>

の様な記載を行うと思いますが、上記だと遅くなってしまいます。

何故なら、antがjunitを起動する際にプロセスのforkを行うのですが、forkはTestCase毎に行われるようです。
複数回のforkを通して網羅率の測定を行う必要がある為、「cobertura.ser」というファイルを
かいして測定を行います。

ところがforkする毎にcobertura.serに、シリアライズ・デシリアライズを行うためのその
オーバーヘッドが大きくなります。実際topコマンド確認するとCPUバウンドな処理である事が分かります。


そこでant 1.6.2より導入された、forkmodeを設定します。

<junit fork="yes" forkmode="once" dir="${basedir}">
....

上記の設定により、junitを実行するプロセスは"一度だけ"起動される為、シリアライズ・デシリアライズのオーバーヘッドが無くなり、非常に高速にテストの実行が可能です。

2011年4月22日金曜日

javascriptでのCIを目指して、phantomjsの環境を作成する4

■概要

前回までで、phantomjsが大体わかったので、jasmine with CoffeeScriptな環境を作成します。

■説明

・CoffeeScriptのコンパイルを楽したい。ここではwatchrを利用してみます。

$ sudo gem install watchr

$ mkdir demo; cd demo
$ mkdir src; mkdir spec
$ vim coffee.watchr

watch(/(src|spec)\/.*\.coffee/) { |md|
  system("coffee -cb #{md[0]}")
}

$ watchr coffee.watchr

(別の端末で)

$ vim src/test.coffee

console.log "a"

$ ls src
test.coffee test.js <= できてます!

・ではjasmineを利用してブラウザからテストを実行します。OOPでは古典的な"カウンター"を作ってみます。
$ wget http://pivotal.github.com/jasmine/downloads/jasmine-standalone-1.0.2.zip
$ unzip *.zip
$ rm *.zip
$ vim spec/CounterSpec.coffee

describe "Counter", ->
  beforeEach ->
    @counter = new Counter()

  describe "#constructor", ->
    it "の初期値は0である", ->
      expect(@counter.value()).toEqual(0)

  describe "#incr", ->
    it "は値を1増加させるはず", ->
      @counter.incr()
      expect(@counter.value()).toEqual(1)

$ vim src/Counter.coffee

class Counter
  constructor: () ->
    @count = 0

  incr: () ->
    @count++

  value: () ->
    @count

$ vim SpecRunner.html (Counter.js/CounterSpec.jsの読み込みを記載する)

ブラウザで http://localhost/demo/SpecRunner.htmlを確認するといい感じです!。
最後にphantomjsからjasmineのSpecRunner.htmlを起動します。
$ vim src/run-jasmine.coffee

if phantom.state.length is 0
  if phantom.args.length isnt 1
    console.log 'Usage: run-jasmine.js URL'
    phantom.exit()
  else
    phantom.state = 'run-jasmine'
    phantom.open phantom.args[0]
else
  window.setInterval ->
    if document.body.querySelector('.finished-at')
      console.log document.body.querySelector('.description').innerText
      for el in document.body.querySelectorAll('div.jasmine_reporter > div.suite.failed')
        console.log ''
        for e in el.querySelectorAll('.description')
          console.log e.innerText
      phantom.exit()
  , 100

$ phantomjs src/run-jasmine.coffee http://localhost/demo/SpecRunner.html
2 specs, 0 failures in 0.039s <= テスト結果が得られてます。いいじゃん!

2011年4月21日木曜日

javascriptでのCIを目指して、phantomjsの環境を作成する3

■概要

前回に引き続きphantomjsのQuickStartを参考にCoffeeScriptを書いてみる。

■説明

・Loading & Rendering

Loadingの説明を見ているといくつかポイントが見えてきます。

・コマンドライン引数に指定されたスクリプトは、複数回呼び出される
※phantom.exit()するまで
・phantom.stateは値が維持されるので、初回呼び出しかどうか判断可能
初回は空文字列
・phantom.openは引数で指定されたページを読み込む
読み込み終了までblockingされる
・phantom.loadStatusはphantom.open後の状態が保持される
"success" もしくは "fail"

という訳で、LoadPage(とRendering)をCoffeeScriptで書いてみます。

$ vim google.coffee

LoadPage = (name, url, action) ->
  if !phantom.state
    phantom.state = name
    phantom.open url
  else
    action()
    phantom.exit()

LoadPage "google", "http://www.google.co.jp", ->
  phantom.render "#{phantom.state}.png"

$ phantomjs google.coffee
$ ls google*
google.coffee google.png

ちゃんと出来ました!なおphantom.viewportSizeの設定をしないとwidth/heightは適当な値になるようです














ちなみにdom treeは読み込み後documentオブジェクトを操作できます。

LoadPage "google", "http://www.google.co.jp", ->
  console.log document.getElementById("prm").innerText

$ phantomjs google.coffee
世界中から寄せられた日本へのメッセージが日本語で見られるサイトを開設しました。


■参照

phantomjsのQuickStart

■雑感

次回は本当にCIができたらな~と思いつつ(ゴールは近いはず)

2011年4月20日水曜日

javascriptでのCIを目指して、phantomjsの環境を作成する2

■概要
前回 phantomjsのインストールに成功したので、色々触って見ます。

・ちなみにphantomjsってCoffeeScriptいけるんですね!

$ phantomjs

Usage: phantomjs [options] script.[js|coffee]
  [script argument [script argument ...]]

・次からはphantomjsのQuickStartを、CoffeeScriptに書き写しながら進めます。

■説明

・まずはhello world

$ vim hello.coffee

console.log "hello, world!"
phantom.exit()

$ phantomjs hello.coffee
hello, world!

・次に同期sleep

$ vim delay.coffee

for t in [10..1]
  console.log t
  phantom.sleep 1000
console.log 'BLAST OFF'
phantom.exit()

$ phantomjs delay.coffee
10
9
...
1
BLAST OFF

・ちなみに非同期sleepは

$ vim adelay.coffee

fibs = [0, 1]

ticker = window.setInterval ->
  console.log fibs[fibs.length - 1]
  fibs.push fibs[fibs.length - 1] + fibs[fibs.length - 2]
  if fibs.length > 10
    window.clearInterval ticker
    phantom.exit()
, 300

$ phantomjs adelay.coffee
1
1
2
...
21
34
functionオブジェクトが最後の引数ではない場合ここにカンマ何ですね。。

・コマンドライン引数は

$ vim arguments.coffee

if phantom.args.length is 0
  console.log 'Try to pass some args when invoking this script!'
else
  phantom.args.forEach (arg, i) -> console.log "#{i}: #{arg}"
phantom.exit()

$ phantomjs arguments.coffee
Try to pass some args when invoking this script!

$ phantomjs arguments.coffee a b c
0: a
1: b
2: c

次回は、感じのページオープンとdom tree周り経由でCIにつなげたいと思う今日この頃

■参考

phantomjsのQuickStart

■雑感

CoffeeScriptの構文は、あまり違和感が無いな~
CoffeeScriptを習得するには、js -> coffeeの翻訳が一番?

■更新履歴

2011/04/20 http://tech.kayac.com/ を参考にさせて頂き、setIntervalの記載方法を変更しました。

2011年4月13日水曜日

javascriptでのCIを目指して、phantomjsの環境を作成する1

■概要
qunit-tapとproveを使ってJSの単体テストのCIをする方法に感化されて、まずは環境づくりに挑戦してみます。

■インストール手順

centos 5.5に環境を作るまでの手順です。

○phantomjsをインストール

http://code.google.com/p/phantomjs/wiki/BuildInstructionsのコメントとかも参考にしながら進めました。

# 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=1

# rpm --import http://packages.atrpms.net/RPM-GPG-KEY.atrpms
# yum install qt47-devel qt47-webkit qt47-webkit-devel

# git clone git://github.com/ariya/phantomjs.git && cd phantomjs
# qmake-qt47
# make
# cp bin/phantomjs /usr/local/bin (PATHの通ってる場所にコピー)

○phantomjsの確認

http://code.google.com/p/phantomjs/を参考に起動を確認しようと思いました

# vim test.js

if (phantom.state.length === 0) {
    phantom.state = 'pizza';
    phantom.open('http://www.google.com/m/local?site=local&q=pizza+in+new+york');
} else {
    var list = document.querySelectorAll('div.bf');
    for (var i in list) {
        console.log(list[i].innerText);
    }
    phantom.exit();
}

# phantomjs test.js
2011-04-13T00:00:32 [WARNING] phantomjs: cannot connect to X server


うーん問題あるみたいですねぇ。

○xvfbの準備

どうもxvfbをインストールして仮想画面を立ち上げないとphantomjsは使えない感じなのでインストール&起動します。

# yum install xorg-x11-server-Xvfb xorg-x11-fonts*
$ Xvfb :2 -screen 0 800x600x24 2> /dev/null &
$ export DISPLAY=:2.0
$ phantomjs test.js

Adrienne's Pizza Bar Restaurant
54 Stone Street, New York, NY
(212) 248-3838 -

John's Pizzeria
278 Bleecker St, New York, New York
(212) 243-1680 -

...


おーなんだか動いてますね!

○/dev/null 指定しないと、何か変なエラーメッセージが出てるんですけど..

FreeFontPath: FPE "built-ins" refcount is 2, should be 1; fixing.
Could not init font path element unix/:7100, removing from list!

=> fontの設定関係の問題っぽいのですが、どうも解決策がわかりません。。とりあえずほっています

○Xvfbどうやって止めたらいいんだ?

$ kill -9 `cat /tmp/.X2-lock`; rm -f /tmp/.X2-lock

こんな感じかな?