rspecとspawn
テストする時とかに、サーバーを必要とするAPIのテストする前にそのサーバーをテストランナーから起動しテストが終わったらシャットダウンするっていう工程をやったりする事があると思うのですが、それをRSpecっていうかRubyでやる方法的な事として、サーバープロセスをspawnしちゃってテスト終了時にプロセスを終了させちゃうとかっていうのを利用する事で出来る模様。という事でやってみた
例題的にはMongoDBとかが分かりやすそう。んまぁ工程的には
- beforeでmongodを実行
- テスト処理
- afterでmongodなプロセスを落とす
的な感じなんなんですが、MongoDB自体のデフォルトなポート辺りは27017辺りだと思うんですが、もしかしたらこれ使っちゃってるかも知れないっていう可能性もあるので使ってないポート辺りを使って動的にサーバーを起動する。んまぁPerlで言うとTest::TCP:empty_port辺りかなと。という事も踏まえつつやるって事で
lib/sample.rb
require "mongo"
class Sample
def self.get
client = Mongo::MongoClient.new(
ENV["MONGO_HOST"] || Mongo::MongoClient::DEFAULT_HOST,
ENV["MONGO_PORT"] || Mongo::MongoClient::DEFAULT_PORT
)
db = client.db("sample")
coll = db.collection("samples")
coll.find_one
end
end
適当にMongoDBのコレクションからfind_oneした結果だけを取る。で接続するサーバーはENVで突っ込んだ情報を元に利用できるような感じ。以下のspec_helperでも補足しているので(ry
spec_helper.rb
require "socket"
require "sample"
# 使うポートを探す
# 参考: https://github.com/fluent/fluent-plugin-mongo/blob/master/test/test_helper.rb
def empty_port
s = TCPServer.open(0)
port = s.addr[1]
s.close
port
end
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
config.filter_run :focus
config.order = "random"
config.before(:all) do
port = empty_port
# Mongo::MongoClientに渡す必要があるが、引数とかでポートを指定しないような場合にENVに突っ込んどいて、そこからconnectする
ENV["MONGO_PORT"] = port.to_s
@pid = spawn(
"/usr/bin/mongod",
"--dbpath=/tmp/mongo",
"--logpath=/tmp/mongo/log",
"--port=#{port}"
)
sleep 3
end
config.after(:all) do
Process.kill("HUP", @pid)
ENV.delete("MONGO_PORT")
end
end
sample_spec.rb
require "spec_helper"
describe Sample do
it "#get" do
sample = Sample.get
expect(sample).not_to be_nil
expect(sample["name"]).to eq("hoge")
end
end
まぁ特にこっちではMongoDBな処理とか一切せずに、単純に書いたクラスのメソッドをテストするだけ
以上。問題はRSpec.configureなbeforeとかafterでやってるけど必要な所でこういう手法使えば良いんじゃねーかと