RSpecでテストHTTPサーバを立てて必要最小限のコンテンツで試験する方法
Rubyでブラウザの自動操作ライブラリの試験を書いていたときに、
こんな感じで必要最低限のHTMLコンテンツのページで試験がしたくなった。
Webmockを使う?
RSpecでHTTPテストサーバーを、みたいなのでぐぐると、なぜかよく出てくる。
https://github.com/bblimke/webmock
ただ、今回は最小コンテンツでHTTPサーバを立てたいのであって、モックしたいわけじゃないので、却下。
SinatraのDSLをRSpecで書けたら良さそうじゃない?
これは完全に自分の好みではあるが、
describe 'click button' do
sinatra do
get '/button.html' do
<<~HTML
<html>
<head><title>button</title></head>
<body>
<button onclick='document.getElementById("mytext").innerHTML="Clicked!"'>
Click here
</button>
<p id="mytext">Not Clicked Yet</p>
</body>
</html>
HTML
end
end
it 'can click button' do
page.goto('/button.html')
page.click('button')
expect(page.Seval('p', 'el => el.textContent')).to eq("Clicked")
end
end
こんな感じで、やりたいことをどストレートに書けたらいいなーと思った。
SinatraでHTTPサーバーを開始・終了するには?
Sinatraのサンプルコードだと、グローバルにHTTPサーバー定義をしているものが多いが、リファレンスやソースをよく読むと
app = Sinatra.new do
get '/hello' do
'Hello World'
end
end
こんな感じでクラスベースでサーバーを定義することができるし、 run!
や quit!
で開始・終了できることがわかる。
app.run! # 開始 (ブロッキングされるので別スレッド必須)
app.quit! # 終了
参考:https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
sinatra do ... end
を実装してみた
RSpec::Core::ExampleGroupに特異メソッドとして sinatra
を定義すればいいので、大枠は以下のように。
module SinatraTestHttpDSL
def sinatra(&block)
...
end
end
RSpec::Core::ExampleGroup.extend(SinatraTestHttpDSL)
んで、sinatraメソッドの実装としては around
フックを仕込んで example.runの前後で app.run!, app.quit! すればいい。
def sinatra(port: 4567, &block)
# HTTPサーバーを定義
app = Sinatra.new(&block)
around do |example|
# HTTPサーバーを起動
Thread.new { app.run!(port: port) }
# HTTPサーバーが疎通可能になるまで待つ。(雑w
loop do
Net::HTTP.get(URI("http://127.0.0.1:#{port}/"))
break
rescue Errno::ECONNREFUSED
sleep 0.1
end
# テスト実行
example.run
# HTTPサーバーを終了
app.quit!
end
end
まとめ
てきとうに↓のように定義すれば
require 'bundler/setup'
# ここから ↓↓↓
module SinatraTestHttpDSL
def sinatra(port: 4567, &block)
require 'net/http'
require 'sinatra/base'
require 'timeout'
# HTTPサーバーを定義
app = Sinatra.new(&block)
around do |example|
# HTTPサーバーを起動
Thread.new { app.run!(port: port) }
# HTTPサーバーが疎通可能になるまで待つ
Timeout.timeout(3) do
loop do
Net::HTTP.get(URI("http://127.0.0.1:#{port}/"))
break
rescue Errno::ECONNREFUSED
sleep 0.1
end
end
# テスト実行
example.run
# HTTPサーバーを終了
app.quit!
end
end
end
RSpec::Core::ExampleGroup.extend(SinatraTestHttpDSL)
# ここまで ↑↑↑
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = '.rspec_status'
.... (後略)
↓こんなかんじで必要最小限のコンテンツのHTTPサーバーを立てた状態でRSpec動かすことができる。
describe 'click button' do
sinatra do
get '/button.html' do
<<~HTML
<html>
<head><title>button</title></head>
<body>
<button onclick='document.getElementById("mytext").innerHTML="Clicked!"'>
Click here
</button>
<p id="mytext">Not Clicked Yet</p>
</body>
</html>
HTML
end
end
it 'can click button' do
page.goto('/button.html')
page.click('button')
expect(page.Seval('p', 'el => el.textContent')).to eq("Clicked")
end
end
実際にやったコード
Author And Source
この問題について(RSpecでテストHTTPサーバを立てて必要最小限のコンテンツで試験する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/YusukeIwaki/items/788412df386f08955486著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .