class ActiveResource::HttpMock
One thing that has always been a pain with remote web services is testing. The HttpMock class makes it easy to test your Active Resource models by creating a set of mock responses to specific requests.
To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to method with an attached block. The block declares a set of URIs with expected input, and the output each request should return. The passed in block has any number of entries in the following generalized format:
mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
-
http_method- The HTTP method to listen for. This can beget,post,patch,put,deleteorhead. -
path- A string, starting with a “/”, defining the URI that is expected to be called. -
request_headers- Headers that are expected along with the request. This argument uses a hash format, such as{ "Content-Type" => "application/json" }. This mock will only trigger if your tests sends a request with identical headers. -
body- The data to be returned. This should be a string of Active Resource parseable content, such as Json. -
status- The HTTP response code, as an integer, to return with the response. -
response_headers- Headers to be returned with the response. Uses the same hash format asrequest_headerslisted above.
In order for a mock to deliver its content, the incoming request must match by the http_method, path and request_headers. If no match is found an InvalidRequestError exception will be raised showing you what request it could not find a response for and also what requests and response pairs have been recorded so you can create a new mock for that request.
Example¶ ↑
def setup @matz = { :person => { :id => 1, :name => "Matz" } }.to_json ActiveResource::HttpMock.respond_to do |mock| mock.post "/people.json", {}, @matz, 201, "Location" => "/people/1.json" mock.get "/people/1.json", {}, @matz mock.put "/people/1.json", {}, nil, 204 mock.delete "/people/1.json", {}, nil, 200 end end def test_get_matz person = Person.find(1) assert_equal "Matz", person.name end
Public Class Methods
Source
# File lib/active_resource/http_mock.rb, line 205 def delete_responses_to_replace(new_responses) new_responses.each { |nr| request_to_remove = nr[0] @@responses = responses.delete_if { |r| r[0] == request_to_remove } } end
Source
# File lib/active_resource/http_mock.rb, line 225 def disable_net_connection! @@net_connection_enabled = false end
Sets all ActiveResource::Connection to use HttpMock instances.
Source
# File lib/active_resource/http_mock.rb, line 220 def enable_net_connection! @@net_connection_enabled = true end
Enables all ActiveResource::Connection instances to use real Net::HTTP instance instead of a mock.
Source
# File lib/active_resource/http_mock.rb, line 238 def net_connection_disabled? !net_connection_enabled? end
Source
# File lib/active_resource/http_mock.rb, line 230 def net_connection_enabled? if defined?(@@net_connection_enabled) @@net_connection_enabled else @@net_connection_enabled = false end end
Checks if real requests can be used instead of the default mock used in tests.
Source
# File lib/active_resource/http_mock.rb, line 103 def requests @@requests ||= [] end
Returns an array of all request objects that have been sent to the mock. You can use this to check if your model actually sent an HTTP request.
Example¶ ↑
def setup @matz = { :person => { :id => 1, :name => "Matz" } }.to_json ActiveResource::HttpMock.respond_to do |mock| mock.get "/people/1.json", {}, @matz end end def test_should_request_remote_service person = Person.find(1) # Call the remote service # This request object has the same HTTP method and path as declared by the mock expected_request = ActiveResource::Request.new(:get, "/people/1.json") # Assert that the mock received, and responded to, the expected request from the model assert ActiveResource::HttpMock.requests.include?(expected_request) end
Source
# File lib/active_resource/http_mock.rb, line 213 def reset! requests.clear responses.clear end
Deletes all logged requests and responses.
Source
# File lib/active_resource/http_mock.rb, line 192 def respond_to(*args) # :yields: mock pairs = args.first || {} reset! if args.last.class != FalseClass if block_given? yield Responder.new(responses) else delete_responses_to_replace pairs.to_a responses.concat pairs.to_a Responder.new(responses) end end
Accepts a block which declares a set of requests and responses for the HttpMock to respond to in the following format:
mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
Example¶ ↑
@matz = { :person => { :id => 1, :name => "Matz" } }.to_json ActiveResource::HttpMock.respond_to do |mock| mock.post "/people.json", {}, @matz, 201, "Location" => "/people/1.json" mock.get "/people/1.json", {}, @matz mock.put "/people/1.json", {}, nil, 204 mock.delete "/people/1.json", {}, nil, 200 end
Alternatively, accepts a hash of {Request => Response} pairs allowing you to generate these the following format:
ActiveResource::Request.new(method, path, body, request_headers) ActiveResource::Response.new(body, status, response_headers)
Example¶ ↑
Request.new(method, path, nil, request_headers)
@matz = { :person => { :id => 1, :name => "Matz" } }.to_json create_matz = ActiveResource::Request.new(:post, '/people.json', @matz, {}) created_response = ActiveResource::Response.new("", 201, {"Location" => "/people/1.json"}) get_matz = ActiveResource::Request.new(:get, '/people/1.json', nil) ok_response = ActiveResource::Response.new("", 200, {}) pairs = {create_matz => created_response, get_matz => ok_response} ActiveResource::HttpMock.respond_to(pairs)
Note, by default, every time you call respond_to, any previous request and response pairs stored in HttpMock will be deleted giving you a clean slate to work on.
If you want to override this behavior, pass in false as the last argument to respond_to
Example¶ ↑
ActiveResource::HttpMock.respond_to do |mock| mock.send(:get, "/people/1", {}, "JSON1") end ActiveResource::HttpMock.responses.length #=> 1 ActiveResource::HttpMock.respond_to(false) do |mock| mock.send(:get, "/people/2", {}, "JSON2") end ActiveResource::HttpMock.responses.length #=> 2
This also works with passing in generated pairs of requests and responses, again, just pass in false as the last argument:
Example¶ ↑
ActiveResource::HttpMock.respond_to do |mock| mock.send(:get, "/people/1", {}, "JSON1") end ActiveResource::HttpMock.responses.length #=> 1 get_matz = ActiveResource::Request.new(:get, '/people/1.json', nil) ok_response = ActiveResource::Response.new("", 200, {}) pairs = {get_matz => ok_response} ActiveResource::HttpMock.respond_to(pairs, false) ActiveResource::HttpMock.responses.length #=> 2 # If you add a response with an existing request, it will be replaced fail_response = ActiveResource::Response.new("", 404, {}) pairs = {get_matz => fail_response} ActiveResource::HttpMock.respond_to(pairs, false) ActiveResource::HttpMock.responses.length #=> 2
Source
# File lib/active_resource/http_mock.rb, line 109 def responses @@responses ||= [] end
Returns the list of requests and their mocked responses. Look up a response for a request using responses.assoc(request).