Permalink
Browse files

Merge pull request #275 from ryankinderman/master-stubbed-lazy-response

Adding support for lazy construction of responses from stubbed requests
  • Loading branch information...
i0rek committed Mar 29, 2013
2 parents e3222c4 + ac18808 commit c53f0261392a0a4b534275e2d841b5c29d71593a
View
@@ -73,13 +73,15 @@ def configure
# @return [ Typhoeus::Expectation ] The expecatation.
#
# @see Typhoeus::Expectation
- def stub(base_url, options = {})
+ def stub(base_url, options = {}, &block)
expectation = Expectation.all.find{ |e| e.base_url == base_url && e.options == options }
- return expectation if expectation
-
- Expectation.new(base_url, options).tap do |new_expectation|
- Expectation.all << new_expectation
+ if expectation.nil?
+ expectation = Expectation.new(base_url, options)
+ Expectation.all << expectation
end
+
+ expectation.and_return &block unless block.nil?
+ expectation
end
# Add before callbacks.
@@ -14,6 +14,30 @@ module Typhoeus
# actual = Typhoeus.get("www.example.com")
# expected == actual
# #=> true
+ #
+ # @example Stub a request and get a lazily-constructed response containing data from actual widgets that exist in the system when the stubbed request is made.
+ # Typhoeus.stub("www.example.com/widgets") do
+ # actual_widgets = Widget.all
+ # Typhoeus::Response.new(
+ # :body => actual_widgets.inject([]) do |ids, widget|
+ # ids << widget.id
+ # end.join(",")
+ # )
+ # end
+ #
+ # @example Stub a request and get a lazily-constructed response in the format requested.
+ # Typhoeus.stub("www.example.com") do |request|
+ # accept = (request.options[:headers]||{})['Accept'] || "application/json"
+ # format = accept.split(",").first
+ # body_obj = { 'things' => [ { 'id' => 'foo' } ] }
+ #
+ # Typhoeus::Response.new(
+ # :headers => {
+ # 'Content-Type' => format
+ # },
+ # :body => SERIALIZERS[format].serialize(body_obj)
+ # )
+ # end
class Expectation
# @api private
@@ -47,15 +71,26 @@ def clear
all.clear
end
- # Returns expecation matching the provided
- # request.
+ # Returns stubbed response matching the
+ # provided request
#
- # @example Find expectation.
- # Typhoeus::Expectation.find_by(request)
+ # @example Find response
+ # Typhoeus::Expectation.response_for(request)
#
- # @return [ Expectation ] The matching expectation.
+ # @return [ Typhoeus::Response ] The stubbed response from a
+ # matching expectation, or nil if no matching expectation
+ # is found.
#
# @api private
+ def response_for(request)
+ expectation = find_by(request)
+ return nil if expectation.nil?
+
+ expectation.response(request)
+ end
+
+ private
+
def find_by(request)
all.find do |expectation|
expectation.matches?(request)
@@ -101,8 +136,8 @@ def stubbed_from(value)
# expectation.and_return(response)
#
# @return [ void ]
- def and_return(response)
- responses << response
+ def and_return(response=nil, &block)
+ responses << (response.nil? ? block : response)
end
# Checks wether this expectation matches
@@ -142,8 +177,11 @@ def responses
# @return [ Response ] The response.
#
# @api private
- def response
+ def response(request)
response = responses.fetch(@response_counter, responses.last)
+ if response.respond_to?(:call)
+ response = response.call(request)
+ end
@response_counter += 1
response.mock = @from || true
response
@@ -15,8 +15,8 @@ module Stubbable
# @example Add the request.
# hydra.add(request)
def add(request)
- if expectation = Expectation.find_by(request)
- request.finish(expectation.response)
+ if response = Expectation.response_for(request)
+ request.finish(response)
else
super
end
@@ -17,8 +17,8 @@ module Stubbable
#
# @return [ Response ] The response.
def run
- if expectation = Expectation.find_by(self)
- finish(expectation.response)
+ if response = Expectation.response_for(self)
+ finish(response)
else
super
end
@@ -47,13 +47,23 @@
end
end
- describe ".find_by" do
+ describe ".response_for" do
let(:request) { Typhoeus::Request.new("") }
+ let(:stubbed_response) { Typhoeus::Response.new }
- it "returns a dummy when expectations not empty" do
+ it "finds a matching expectation and returns its next response" do
Typhoeus::Expectation.all << expectation
expectation.should_receive(:matches?).with(request).and_return(true)
- expect(Typhoeus::Expectation.find_by(request)).to eq(expectation)
+ expectation.should_receive(:response).with(request).and_return(stubbed_response)
+
+ response = Typhoeus::Expectation.response_for(request)
+
+ expect(response).to be(stubbed_response)
+ end
+
+ it "returns nil if no matching expectation is found" do
+ response = Typhoeus::Expectation.response_for(request)
+ expect(response).to be(nil)
end
end
@@ -83,6 +93,14 @@
expect(expectation.responses).to eq([1, 2])
end
end
+
+ context "when block" do
+ it "adds to responses" do
+ block = Proc.new {}
+ expectation.and_return &block
+ expect(expectation.responses).to eq([block])
+ end
+ end
end
describe "#responses" do
@@ -92,13 +110,32 @@
end
describe "#response" do
+ let(:request) { Typhoeus::Request.new("") }
+
before { expectation.instance_variable_set(:@responses, responses) }
context "when one response" do
- let(:responses) { [Typhoeus::Response.new] }
+ context "is pre-constructed" do
+ let(:responses) { [Typhoeus::Response.new] }
+
+ it "returns response" do
+ expect(expectation.response(request)).to be(responses[0])
+ end
+ end
- it "returns response" do
- expect(expectation.response).to be(responses[0])
+ context "is lazily-constructed" do
+ def construct_response(request)
+ @request_from_response_construction = request
+ lazily_constructed_response
+ end
+
+ let(:lazily_constructed_response) { Typhoeus::Response.new }
+ let(:responses) { [ Proc.new { |request| construct_response(request) } ] }
+
+ it "returns response" do
+ expect(expectation.response(request)).to be(lazily_constructed_response)
+ expect(@request_from_response_construction).to be(request)
+ end
end
end
@@ -107,7 +144,7 @@
it "returns one by one" do
3.times do |i|
- expect(expectation.response).to eq(responses[i])
+ expect(expectation.response(request)).to be(responses[i])
end
end
end
@@ -16,23 +16,23 @@
context "when true" do
it "calls super" do
Typhoeus.before { true }
- Typhoeus::Expectation.should_receive(:find_by)
+ Typhoeus::Expectation.should_receive(:response_for)
hydra.add(request)
end
end
context "when false" do
it "doesn't call super" do
Typhoeus.before { false }
- Typhoeus::Expectation.should_receive(:find_by).never
+ Typhoeus::Expectation.should_receive(:response_for).never
hydra.add(request)
end
end
context "when response" do
it "doesn't call super" do
Typhoeus.before { Typhoeus::Response.new }
- Typhoeus::Expectation.should_receive(:find_by).never
+ Typhoeus::Expectation.should_receive(:response_for).never
hydra.add(request)
end
end
@@ -43,7 +43,7 @@
before { 3.times { Typhoeus.before { |r| String.new(r.base_url) } } }
it "calls super" do
- Typhoeus::Expectation.should_receive(:find_by)
+ Typhoeus::Expectation.should_receive(:response_for)
hydra.add(request)
end
@@ -61,7 +61,7 @@
end
it "doesn't call super" do
- Typhoeus::Expectation.should_receive(:find_by).never
+ Typhoeus::Expectation.should_receive(:response_for).never
hydra.add(request)
end
@@ -75,7 +75,7 @@
context "when no before" do
it "calls super" do
- Typhoeus::Expectation.should_receive(:find_by)
+ Typhoeus::Expectation.should_receive(:response_for)
hydra.add(request)
end
end
@@ -9,7 +9,7 @@
before { Typhoeus.stub(base_url).and_return(response) }
describe "#add" do
- it "checks expactations" do
+ it "checks expectations" do
hydra.add(request)
end
@@ -15,15 +15,15 @@
context "when true" do
it "calls super" do
Typhoeus.before { true }
- Typhoeus::Expectation.should_receive(:find_by)
+ Typhoeus::Expectation.should_receive(:response_for)
request.run
end
end
context "when false" do
it "doesn't call super" do
Typhoeus.before { false }
- Typhoeus::Expectation.should_receive(:find_by).never
+ Typhoeus::Expectation.should_receive(:response_for).never
request.run
end
@@ -36,7 +36,7 @@
context "when a response" do
it "doesn't call super" do
Typhoeus.before { Typhoeus::Response.new }
- Typhoeus::Expectation.should_receive(:find_by).never
+ Typhoeus::Expectation.should_receive(:response_for).never
request.run
end
@@ -52,7 +52,7 @@
before { 3.times { Typhoeus.before { |r| String.new(r.base_url) } } }
it "calls super" do
- Typhoeus::Expectation.should_receive(:find_by)
+ Typhoeus::Expectation.should_receive(:response_for)
request.run
end
@@ -70,7 +70,7 @@
end
it "doesn't call super" do
- Typhoeus::Expectation.should_receive(:find_by).never
+ Typhoeus::Expectation.should_receive(:response_for).never
request.run
end
@@ -84,7 +84,7 @@
context "when no before" do
it "calls super" do
- Typhoeus::Expectation.should_receive(:find_by)
+ Typhoeus::Expectation.should_receive(:response_for)
request.run
end
end
@@ -7,8 +7,8 @@
before { Typhoeus.stub(base_url).and_return(response) }
- describe "#queue" do
- it "checks expactations" do
+ describe "#run" do
+ it "checks expectations" do
request.run
end
View
@@ -21,7 +21,22 @@
describe ".stub" do
let(:base_url) { "www.example.com" }
+ shared_examples "lazy response construction" do
+ it "calls the block to construct a response when a request matches the stub" do
+ expected_response = Typhoeus::Response.new
+ Typhoeus.stub(base_url) do |request|
+ expected_response
+ end
+
+ response = Typhoeus.get(base_url)
+
+ expect(response).to be(expected_response)
+ end
+ end
+
context "when no similar expectation exists" do
+ include_examples "lazy response construction"
+
it "returns expectation" do
expect(Typhoeus.stub(base_url)).to be_a(Typhoeus::Expectation)
end
@@ -33,6 +48,8 @@
end
context "when similar expectation exists" do
+ include_examples "lazy response construction"
+
let(:expectation) { Typhoeus::Expectation.new(base_url) }
before { Typhoeus::Expectation.all << expectation }

0 comments on commit c53f026

Please sign in to comment.