Test::mysqld とは
Perl に Test::mysqld というモジュールがある。テストを実行するときに MySQL のインスタンスをよしなに起動してくれる。
同じテストスイート (プロジェクト、リポジトリ) を並行して実行する場合、データベースの接続先は同じなので複数のテスト実行プロセスが存在すると同じデータベースのインスタンスに接続するため、挿入や削除あるいは更新といった操作を実行すると他のテスト実行プロセスに予期せぬ影響を与えかねない、という問題がある。
Test::mysqld は空いているポートを見つけてそこで listen する MySQL サーバを起動してくれて、環境変数に DSN を設定してテストスイートではこの DSN に接続することで、接続先を決めるコードを共有したまま実際に接続する DB のインスタンスを分けることができるようになっている。
その他、機能があるけれど、Test::mysqld の「テスト実行時にデータベースのインスタンスを起動する」という機能が便利そうだと思った。
テスト実行とデータベースの起動
自分は Web アプリケーションを書くことが多く、データの永続化に RDBMS を使うことも多い。
もちろんテストも書くが、テストを実行するときに RDBMS が起動されている必要がある。
OS X だと Launch Agents に登録しておいて勝手に起動するようにしてもいいけれど、あまり無駄なプロセスを立ち上げておきたくもない。
しかし、いちいち手で起動するのもめんどうなので、テストを実行するときに一緒に起動し、テストの実行が終わったら終了するようにしたいと思った。
Foreman を使う
Foreman は Ruby で書かれたプロセス管理ツールで Procfile に同時に起動するプロセスを書いておくと foreman start
で一斉に起動してくれて、いずれかのプロセスが終了したら他のプロセスも終了させてくれるというようなことをしてくれる。
db: postgres -D $POSTGRES_ROOT test: bundle exec rake test
test/Procfile を上記のような内容で作る。
require 'rake/testtask' require 'foreman/cli' Rake::TestTask.new(:test) namespace :standalone do test :test do Foreman::CLI.start(%w(start -f test/Procfile)) end end
Rakefile に上記のようなタスクを定義して `rake standalone:test` を実行すると Foreman で postgres
と rake
が実行され、rake
が終了すると postgres
も終了する。
(ちなみに Foreman::CLI
は Thor
を継承している。Thor は Ruby で書かれた CLI アプリケーション・フレームワーク。)
実際のテスト実行のためのタスクは Rake::TestTask
によって定義されているけれど、別にテストを実行するタスクの定義の仕方はなんでもいいし、Rake タスクでなくともよい。