2014年4月1日火曜日

Cucumberで各シナリオのテスト実行前にDBリセット

Cucumberでテストを実行しようとするときに、各シナリオ実行前にデータベースをテスト用の初期状態にセットしておきたいって思ったんですよ。各シナリオ内部で書いてもいいのかもしれませんが、毎回同じ状態にセットするのも面倒ではあります。

そこで、フックを利用します。support/env.rb にフック登録用メソッドで処理を定義すると、決められたタイミングで実行してくれます。今回はシナリオ実行前なので、Beforeメソッドを使います。

さらに、DBリセット時のログをターミナル上に出してしまうと、テスト実行結果の出力と混じって見づらくなってしまいます。そこで、DBリセット時はログをファイルに吐き出すことにします。

Padrinoフレームワーク上で、ActiveRecordを使っている時のsupport/env.rb の一例を書いておきます。

# encoding: utf-8
RACK_ENV = 'test' unless defined?(RACK_ENV)
require File.expand_path(File.dirname(__FILE__) + "/../../config/boot")

require 'capybara/cucumber'
require 'rspec/expectations'
require 'thor'

##
# You can handle all padrino applications using instead:
#   Padrino.application
Capybara.app = ProjectName::App.tap { |app|  }

# ログファイル用のディレクトリ・ファイルの準備
log_dir = Padrino.root('log', 'cucumber')
log_path = log_dir + '/before.log'
FileUtils.mkdir_p(log_dir) unless FileTest.exist?(log_dir)
File.open(log_path, 'w').close

# 標準出力をバックアップ
stdout_old = $stdout.dup
# テーブル一覧を取得(テーブル名からモデルクラス名を求めて定数化)
tables = (ActiveRecord::Base.connection.tables - ['schema_migrations']).map { |t| t.classify.constantize }
# データファイル
seed_file = Padrino.root('db', 'seeds.rb')
# フック実行済み回数
hook_done_count = 0

# 各シナリオの実行前に起動するフック
Before do |scenario|
  # 標準出力をログファイルに吐き出す
  $stdout.reopen(log_path, 'a')
  $stdout.write("\n") if hook_done_count > 0
  $stdout.write(Time.now.instance_eval { '%s.%03d'%[strftime('%Y/%m/%d %H:%M:%S'), (usec / 1000.0).round] } + "\n")
  $stdout.write('機能: ' + scenario.feature.name.split("\n").first + "\n")
  $stdout.write('シナリオ: ' + scenario.name.split("\n").first + "\n")
  $stdout.write("\n")

  # データベース初期化
  tables.each do |tbl|
    tbl.destroy_all
  end
  load(seed_file) if File.exist?(seed_file)

  # 標準出力を元に戻す
  $stdout.reopen(stdout_old)

  hook_done_count += 1
end

def shell
  @_shell ||= Thor::Base.shell.new
end

補足すると、seeds.rbファイルをロードすることにより、テストの初期状態データセットをロードすることになっていますが、その中でThorを使い、shellという名前でThorオブジェクトを扱っているので、Thorオブジェクトを返すshellメソッドを定義しています。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

0 件のコメント:

コメントを投稿