前回
今回は、
RSpecの自動テストの中からサーバを起動停止する
wwは、
# spec/miniblog_client_spec.rb
$:.unshift File.expand_path("../lib", File.dirname(__FILE__))
require 'miniblog_client'
require 'ww'
describe MiniblogClient do
before(:all) do
WW::Server.handler = :webrick
WW::Server[:miniblog] ||= WW::Server.build_double(3080) do
m_offset = 0
spy.get("/messages/:user.json") do |user|
content_type "application/json"
t = Time.local(2010, 3, 13, 12, 34 + (m_offset += 1), 56)
body = [
{:message => "#{user}です。ミニブログ始めました", :posted_on => t.iso8601},
{:message => "2つめの#{user}つぶやきです", :posted_on => (t + 10*60).iso8601},
].to_json
end
end
WW::Server.start_once(:miniblog)
end
it "サーバが正常に起動していること" do
expect {
TCPSocket.open('localhost', 3080).close
}.should_not raise_exception(Errno::ECONNREFUSED)
end
end
アクションを定義しているブロックは、
サーバを起動させるには、
サーバへのリクエストをモックする
では、
リクエストの有無をモックで検証する
wwでは2種類の方法でモックを定義できます。
一つ目はWW::Server.
今回はpost_
diff --git a/spec/miniblog_client_spec.rb b/spec/miniblog_client_spec.rb
@@ -24,4 +24,22 @@ describe MiniblogClient do
expect { TCPSocket.open("localhost", 3080).close }.
should_not raise_exception(Errno::ECONNREFUSED)
end
+
+ describe "#post_entry" do
+ before do
+ WW::Server.mock(:miniblog).post("/messages") do
+ ""
+ end
+ conn = Connection.new("localhost", 3080)
+ @client = MiniblogClient.new(conn)
+ end
+
+ after do
+ WW::Server.verify(:miniblog)
+ end
+
+ it "/messageにメッセージをPOSTすること" do
+ @client.post_entry("moro", "こんばんは")
+ end
+ end
end
まずは、
# lib/miniblog_client.rb (※ ソースのディレクトリを、作業ルートからlibに移しています)
diff --git a/lib/miniblog_client.rb b/lib/miniblog_client.rb
@@ -18,6 +18,9 @@ class MiniblogClient
newer_first ? entries.reverse : entries
end
+
+ def post_entry(*args)
+ end
end
class Connection
この状態でテストを実行します。モックしている、
$ spec -fn -c spec/miniblog_client_spec.rb MiniblogClient サーバが正常に起動していること #post_entry /messageにメッセージをPOSTすること (FAILED - 1) 1) Ww::Double::MockError in 'MiniblogClient #post_entry /messageにメッセージをPOSTすること' Ww::Double::MockError /Users/moro/tmp/gihyo.jp_ww/spec/miniblog_client_spec.rb:38: Finished in 0.284092 seconds 2 examples, 1 failure
予想通りテストが失敗することを確認できたので、
diff --git a/lib/miniblog_client.rb b/lib/miniblog_client.rb
@@ -1,6 +1,8 @@
require 'rubygems'
require 'json'
require 'open-uri'
+require 'net/http'
+require 'rack/utils'
class MiniblogClient
def initialize(conn, *friends)
@@ -17,7 +19,8 @@ class MiniblogClient
newer_first ? entries.reverse : entries
end
- def post_entry(*args)
+ def post_entry(name, message)
+ @connection.post("/messages", "user" => name, "message" => message)
end
end
@@ -28,6 +31,14 @@ class Connection
def get(abs_path)
open("http://#{@host}:#{@port}#{abs_path}").read
end
+
+ def post(abs_path, data)
+ req = Net::HTTP::Post.new(abs_path)
+ req.body = data.map { |k,v|
+ "#{Rack::Utils.escape(k.to_s)}=#{Rack::Utils.escape(v.to_s)}"
+ }.join("&")
+ Net::HTTP.start(@host, @port) { |http| http.request(req) }
+ end
end
if __FILE__ == $0
これでテストが通るようになりました。試しに実行してみましょう。
$ spec -fn -c spec/miniblog_client_spec.rb MiniblogClient サーバが正常に起動していること #post_entry /messageにメッセージをPOSTすること Finished in 0.345286 seconds 2 examples, 0 failures
期待するリクエストの内容つきでモックする
さらに、
たとえば、
diff --git a/spec/miniblog_client_spec.rb b/spec/miniblog_client_spec.rb
@@ -27,7 +27,7 @@ describe MiniblogClient do
describe "#post_entry" do
before do
- WW::Server.mock(:miniblog).post("/messages") do
+ WW::Server.mock(:miniblog, "message" => "こんばんは").post("/messages") do
""
end
conn = Connection.new("localhost", 3080)
こうすると、
スパイのリクエストの状況を検証する
前回紹介した、
たとえば、
diff --git a/spec/miniblog_client_spec.rb b/spec/miniblog_client_spec.rb
@@ -42,4 +42,15 @@ describe MiniblogClient do
@client.post_entry("moro", "こんばんは")
end
end
+
+ describe "#entry_list" do
+ before do
+ conn = Connection.new("localhost", 3080)
+ client = MiniblogClient.new(conn, "alice", "bob", "charls")
+
+ client.entry_list
+ end
+ subject { WW::Server[:miniblog] }
+ it { should have(3).requests }
+ end
end
スパイとして定義したアクションへのリクエストは、
このテストを実行すると、次のようにパスします。
$ spec -fn -c spec/miniblog_client_spec.rb MiniblogClient サーバが正常に起動していること #post_entry /messageにメッセージをPOSTすること #entry_list should have 3 requests Finished in 0.197325 seconds 3 examples, 0 failures
モックとスパイを使い分ける判断基準ですが、
おわりに
今回は、
wwは現在も開発中であり、
外部サービスとの連携は、