webmock 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/CHANGELOG.md +35 -0
  2. data/README.md +10 -24
  3. data/VERSION +1 -1
  4. data/lib/webmock.rb +4 -0
  5. data/lib/webmock/api.rb +1 -1
  6. data/lib/webmock/assertion_failure.rb +2 -4
  7. data/lib/webmock/cucumber.rb +8 -0
  8. data/lib/webmock/errors.rb +13 -1
  9. data/lib/webmock/http_lib_adapters/curb.rb +2 -2
  10. data/lib/webmock/http_lib_adapters/em_http_request.rb +31 -17
  11. data/lib/webmock/http_lib_adapters/httpclient.rb +3 -3
  12. data/lib/webmock/http_lib_adapters/net_http.rb +2 -2
  13. data/lib/webmock/http_lib_adapters/patron.rb +2 -2
  14. data/lib/webmock/request_execution_verifier.rb +18 -4
  15. data/lib/webmock/request_pattern.rb +1 -1
  16. data/lib/webmock/request_registry.rb +13 -28
  17. data/lib/webmock/request_signature.rb +15 -2
  18. data/lib/webmock/rspec.rb +32 -1
  19. data/lib/webmock/{adapters/rspec → rspec}/matchers.rb +4 -0
  20. data/lib/webmock/{adapters/rspec → rspec/matchers}/request_pattern_matcher.rb +0 -0
  21. data/lib/webmock/{adapters/rspec → rspec/matchers}/webmock_matcher.rb +0 -0
  22. data/lib/webmock/stub_registry.rb +43 -0
  23. data/lib/webmock/stub_request_snippet.rb +27 -0
  24. data/lib/webmock/test_unit.rb +20 -1
  25. data/lib/webmock/util/hash_counter.rb +9 -4
  26. data/lib/webmock/util/hash_keys_stringifier.rb +23 -0
  27. data/lib/webmock/webmock.rb +14 -4
  28. data/spec/curb_spec.rb +1 -1
  29. data/spec/curb_spec_helper.rb +0 -4
  30. data/spec/em_http_request_spec.rb +5 -0
  31. data/spec/em_http_request_spec_helper.rb +0 -4
  32. data/spec/errors_spec.rb +17 -0
  33. data/spec/httpclient_spec_helper.rb +0 -4
  34. data/spec/net_http_spec_helper.rb +2 -8
  35. data/spec/patron_spec_helper.rb +4 -11
  36. data/spec/request_execution_verifier_spec.rb +14 -4
  37. data/spec/request_registry_spec.rb +29 -80
  38. data/spec/request_signature_spec.rb +77 -3
  39. data/spec/spec_helper.rb +0 -18
  40. data/spec/stub_registry_spec.rb +86 -0
  41. data/spec/stub_request_snippet_spec.rb +47 -0
  42. data/spec/util/hash_counter_spec.rb +15 -0
  43. data/spec/util/hash_keys_stringifier_spec.rb +27 -0
  44. data/spec/webmock_shared.rb +63 -66
  45. data/test/test_helper.rb +5 -1
  46. data/test/test_webmock.rb +5 -2
  47. data/webmock.gemspec +17 -7
  48. metadata +19 -9
  49. data/lib/webmock/adapters/rspec.rb +0 -33
  50. data/lib/webmock/adapters/test_unit.rb +0 -19
@@ -1,5 +1,40 @@
1
1
  #Changelog
2
2
 
3
+ ## 1.6.0
4
+
5
+ * Simplified integration with Test::Unit, RSpec and Cucumber. Now only a single file has to be required i.e.
6
+
7
+ require 'webmock/test_unit'
8
+ require 'webmock/rspec'
9
+ require 'webmock/cucumber'
10
+
11
+ * The error message on unstubbed request now contains code snippet which can be used to stub this request. Thanks to Martyn Loughran for suggesting this feature.
12
+
13
+ * The expectation failure message now contains a list of made requests. Thanks to Martyn Loughran for suggesting this feature.
14
+
15
+ * Added `WebMock.print_executed_requests` method which can be useful to find out what requests were made until a given point.
16
+
17
+ * em-http-request adapter is now activated by replacing EventMachine::HttpRequest constant, instead of monkeypatching the original class.
18
+
19
+ This technique is borrowed from em-http-request native mocking module. It allows switching WebMock adapter on an off, and using it interchangeably with em-http-request native mocking i.e:
20
+
21
+ EventMachine::WebMockHttpRequest.activate!
22
+ EventMachine::WebMockHttpRequest.deactivate!
23
+
24
+ Thanks to Martyn Loughran for suggesting this feature.
25
+
26
+ * `WebMock.reset_webmock` is deprecated in favour of new `WebMock.reset!`
27
+
28
+ * Fixed integration with Cucumber. Previously documented example didn't work with new versions of Cucumber.
29
+
30
+ * Fixed stubbing requests with body declared as a hash. Thanks to Erik Michaels-Ober for reporting the issue.
31
+
32
+ * Fixed issue with em-http-request adapter which didn't work when :query option value was passed as a string, not a hash. Thanks to Chee Yeo for reporting the issue.
33
+
34
+ * Fixed problem with assert_requested which didn't work if used outside rspec or test/unit
35
+
36
+ * Removed dependency on json gem
37
+
3
38
  ## 1.5.0
4
39
 
5
40
  * Support for dynamically evaluated raw responses recorded with `curl -is` <br/>
data/README.md CHANGED
@@ -25,17 +25,19 @@ Supported HTTP libraries
25
25
 
26
26
  ##Installation
27
27
 
28
- gem install webmock --source http://gemcutter.org
28
+ gem install webmock --source http://gemcutter.org
29
+
30
+ ### or to install the latest development version from github master
31
+
32
+ git clone http://github.com/bblimke/webmock.git
33
+ cd webmock
34
+ rake install
29
35
 
30
36
  ### Test::Unit
31
37
 
32
38
  Add the following code to `test/test_helper.rb`
33
39
 
34
40
  require 'webmock/test_unit'
35
-
36
- class Test::Unit::TestCase
37
- include WebMock::API
38
- end
39
41
 
40
42
  ### RSpec
41
43
 
@@ -43,32 +45,16 @@ Add the following code to `spec/spec_helper`:
43
45
 
44
46
  require 'webmock/rspec'
45
47
 
46
- Spec::Runner.configure do |config|
47
- config.include WebMock::API
48
- end
49
-
50
- ### RSpec 2
51
-
52
- Add the following code to `spec/spec_helper`:
53
-
54
- require 'webmock/rspec'
55
-
56
- RSpec.configure do |config|
57
- config.include WebMock::API
58
- end
59
-
60
48
  ### Cucumber
61
49
 
62
50
  Add the following code to `features/support/env.rb`
63
51
 
64
- require 'webmock/rspec'
65
- World(WebMock::API, WebMock::Matchers)
52
+ require 'webmock/cucumber'
66
53
 
67
54
  You can also use WebMock outside a test framework:
68
55
 
69
56
  require 'webmock'
70
57
  include WebMock::API
71
- include WebMock::Matchers
72
58
 
73
59
  ## Examples
74
60
 
@@ -392,13 +378,13 @@ This forces WebMock Net::HTTP adapter to always connect on `Net::HTTP.start`.
392
378
 
393
379
  ## Clearing stubs and request history
394
380
 
395
- If you want to reset all current stubs and history of requests use `WebMock.reset_webmock`
381
+ If you want to reset all current stubs and history of requests use `WebMock.reset!`
396
382
 
397
383
  stub_request(:any, "www.example.com")
398
384
 
399
385
  Net::HTTP.get('www.example.com', '/') # ===> Success
400
386
 
401
- reset_webmock
387
+ WebMock.reset!
402
388
 
403
389
  Net::HTTP.get('www.example.com', '/') # ===> Failure
404
390
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.0
1
+ 1.6.0
@@ -16,6 +16,7 @@ require 'webmock/errors'
16
16
  require 'webmock/util/uri'
17
17
  require 'webmock/util/headers'
18
18
  require 'webmock/util/hash_counter'
19
+ require 'webmock/util/hash_keys_stringifier'
19
20
 
20
21
  require 'webmock/request_pattern'
21
22
  require 'webmock/request_signature'
@@ -23,10 +24,13 @@ require 'webmock/responses_sequence'
23
24
  require 'webmock/request_stub'
24
25
  require 'webmock/response'
25
26
 
27
+ require 'webmock/stub_request_snippet'
28
+
26
29
  require 'webmock/assertion_failure'
27
30
  require 'webmock/request_execution_verifier'
28
31
  require 'webmock/config'
29
32
  require 'webmock/callback_registry'
30
33
  require 'webmock/request_registry'
34
+ require 'webmock/stub_registry'
31
35
  require 'webmock/api'
32
36
  require 'webmock/webmock'
@@ -3,7 +3,7 @@ module WebMock
3
3
  extend self
4
4
 
5
5
  def stub_request(method, uri)
6
- WebMock::RequestRegistry.instance.register_request_stub(WebMock::RequestStub.new(method, uri))
6
+ WebMock::StubRegistry.instance.register_request_stub(WebMock::RequestStub.new(method, uri))
7
7
  end
8
8
 
9
9
  alias_method :stub_http_request, :stub_request
@@ -1,13 +1,11 @@
1
1
  module WebMock
2
2
  class AssertionFailure
3
+ @error_class = RuntimeError
3
4
  class << self
4
- attr_writer :error_class
5
- @error_class = RuntimeError
6
-
5
+ attr_accessor :error_class
7
6
  def failure(message)
8
7
  raise @error_class.new(message)
9
8
  end
10
-
11
9
  end
12
10
  end
13
11
  end
@@ -0,0 +1,8 @@
1
+ require 'webmock'
2
+ require 'webmock/rspec/matchers'
3
+
4
+ World(WebMock::API, WebMock::Matchers)
5
+
6
+ After do
7
+ WebMock.reset!
8
+ end
@@ -2,7 +2,19 @@ module WebMock
2
2
 
3
3
  class NetConnectNotAllowedError < StandardError
4
4
  def initialize(request_signature)
5
- super("Real HTTP connections are disabled. Unregistered request: #{request_signature}")
5
+ text = "Real HTTP connections are disabled. Unregistered request: #{request_signature}"
6
+ text << stubbing_instructions(request_signature)
7
+ super(text)
8
+ end
9
+
10
+ private
11
+
12
+ def stubbing_instructions(request_signature)
13
+ text = "\n\n"
14
+ text << "You can stub this request with the following snippet:\n\n"
15
+ text << WebMock::StubRequestSnippet.new(request_signature).to_s
16
+ text << "\n\n" + "="*60
17
+ text
6
18
  end
7
19
  end
8
20
 
@@ -6,8 +6,8 @@ if defined?(Curl)
6
6
  request_signature = build_request_signature
7
7
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
8
8
 
9
- if WebMock::RequestRegistry.instance.registered_request?(request_signature)
10
- webmock_response = WebMock::RequestRegistry.instance.response_for_request(request_signature)
9
+ if WebMock::StubRegistry.instance.registered_request?(request_signature)
10
+ webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
11
11
  build_curb_response(webmock_response)
12
12
  WebMock::CallbackRegistry.invoke_callbacks(
13
13
  {:lib => :curb}, request_signature, webmock_response)
@@ -1,9 +1,13 @@
1
1
  if defined?(EventMachine::HttpRequest)
2
2
 
3
3
  module EventMachine
4
- class HttpRequest
4
+ OriginalHttpRequest = HttpRequest unless const_defined?(:OriginalHttpRequest)
5
5
 
6
- class WebMockFakeHttpClient < EventMachine::HttpClient
6
+ class WebMockHttpRequest < EventMachine::HttpRequest
7
+
8
+ include HttpEncoding
9
+
10
+ class WebMockHttpClient < EventMachine::HttpClient
7
11
 
8
12
  def setup(response, uri, error = nil)
9
13
  @uri = uri
@@ -17,7 +21,7 @@ if defined?(EventMachine::HttpRequest)
17
21
  end
18
22
  end
19
23
  end
20
-
24
+
21
25
  def unbind
22
26
  end
23
27
 
@@ -30,11 +34,11 @@ if defined?(EventMachine::HttpRequest)
30
34
 
31
35
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
32
36
 
33
- if WebMock::RequestRegistry.instance.registered_request?(request_signature)
34
- webmock_response = WebMock::RequestRegistry.instance.response_for_request(request_signature)
37
+ if WebMock::StubRegistry.instance.registered_request?(request_signature)
38
+ webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
35
39
  WebMock::CallbackRegistry.invoke_callbacks(
36
- {:lib => :em_http_request}, request_signature, webmock_response)
37
- client = WebMockFakeHttpClient.new(nil)
40
+ {:lib => :em_http_request}, request_signature, webmock_response)
41
+ client = WebMockHttpClient.new(nil)
38
42
  client.on_error("WebMock timeout error") if webmock_response.should_timeout
39
43
  client.setup(make_raw_response(webmock_response), @uri,
40
44
  webmock_response.should_timeout ? "WebMock timeout error" : nil)
@@ -54,13 +58,13 @@ if defined?(EventMachine::HttpRequest)
54
58
  raise WebMock::NetConnectNotAllowedError.new(request_signature)
55
59
  end
56
60
  end
57
-
61
+
58
62
  alias_method :send_request_without_webmock, :send_request
59
63
  alias_method :send_request, :send_request_with_webmock
60
-
64
+
61
65
 
62
66
  private
63
-
67
+
64
68
  def build_webmock_response(http)
65
69
  webmock_response = WebMock::Response.new
66
70
  webmock_response.status = [http.response_header.status, http.response_header.http_reason]
@@ -78,7 +82,7 @@ if defined?(EventMachine::HttpRequest)
78
82
  options = @options
79
83
  method = @method
80
84
  uri = @uri
81
- end
85
+ end
82
86
 
83
87
  if options[:authorization] || options['authorization']
84
88
  auth = (options[:authorization] || options['authorization'])
@@ -87,9 +91,9 @@ if defined?(EventMachine::HttpRequest)
87
91
  options.reject! {|k,v| k.to_s == 'authorization' } #we added it to url userinfo
88
92
  uri.userinfo = userinfo
89
93
  end
90
-
91
- uri.query_values = (uri.query_values || {}).merge(options[:query]) if options[:query]
92
-
94
+
95
+ uri.query = encode_query(@req.uri, options[:query]).slice(/\?(.*)/, 1)
96
+
93
97
  WebMock::RequestSignature.new(
94
98
  method.downcase.to_sym,
95
99
  uri.to_s,
@@ -99,11 +103,11 @@ if defined?(EventMachine::HttpRequest)
99
103
  end
100
104
 
101
105
 
102
- def make_raw_response(response)
106
+ def make_raw_response(response)
103
107
  response.raise_error_if_any
104
-
108
+
105
109
  status, headers, body = response.status, response.headers, response.body
106
-
110
+
107
111
  response_string = []
108
112
  response_string << "HTTP/1.1 #{status[0]} #{status[1]}"
109
113
 
@@ -116,8 +120,18 @@ if defined?(EventMachine::HttpRequest)
116
120
  response_string.join("\n")
117
121
  end
118
122
 
123
+ def self.activate!
124
+ EventMachine.send(:remove_const, :HttpRequest)
125
+ EventMachine.send(:const_set, :HttpRequest, WebMockHttpRequest)
126
+ end
119
127
 
128
+ def self.deactivate!
129
+ EventMachine.send(:remove_const, :HttpRequest)
130
+ EventMachine.send(:const_set, :HttpRequest, OriginalHttpRequest)
131
+ end
120
132
  end
121
133
  end
122
134
 
135
+ EventMachine::WebMockHttpRequest.activate!
136
+
123
137
  end
@@ -15,8 +15,8 @@ if defined?(::HTTPClient)
15
15
 
16
16
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
17
17
 
18
- if WebMock::RequestRegistry.instance.registered_request?(request_signature)
19
- webmock_response = WebMock::RequestRegistry.instance.response_for_request(request_signature)
18
+ if WebMock::StubRegistry.instance.registered_request?(request_signature)
19
+ webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
20
20
  response = build_httpclient_response(webmock_response, stream, &block)
21
21
  res = conn.push(response)
22
22
  WebMock::CallbackRegistry.invoke_callbacks(
@@ -46,7 +46,7 @@ if defined?(::HTTPClient)
46
46
  req = create_request(method, uri, query, body, extheader)
47
47
  request_signature = build_request_signature(req)
48
48
 
49
- if WebMock::RequestRegistry.instance.registered_request?(request_signature) ||
49
+ if WebMock::StubRegistry.instance.registered_request?(request_signature) ||
50
50
  WebMock.net_connect_allowed?(request_signature.uri)
51
51
  do_request_async_without_webmock(method, uri, query, body, extheader)
52
52
  else
@@ -51,9 +51,9 @@ module Net #:nodoc: all
51
51
 
52
52
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
53
53
 
54
- if WebMock::RequestRegistry.instance.registered_request?(request_signature)
54
+ if WebMock::StubRegistry.instance.registered_request?(request_signature)
55
55
  @socket = Net::HTTP.socket_type.new
56
- webmock_response = WebMock::RequestRegistry.instance.response_for_request(request_signature)
56
+ webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
57
57
  WebMock::CallbackRegistry.invoke_callbacks(
58
58
  {:lib => :net_http}, request_signature, webmock_response)
59
59
  build_net_http_response(webmock_response, &block)
@@ -8,8 +8,8 @@ if defined?(Patron)
8
8
 
9
9
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
10
10
 
11
- if WebMock::RequestRegistry.instance.registered_request?(request_signature)
12
- webmock_response = WebMock::RequestRegistry.instance.response_for_request(request_signature)
11
+ if WebMock::StubRegistry.instance.registered_request?(request_signature)
12
+ webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
13
13
  handle_file_name(req, webmock_response)
14
14
  res = build_patron_response(webmock_response)
15
15
  WebMock::CallbackRegistry.invoke_callbacks(
@@ -27,15 +27,29 @@ module WebMock
27
27
 
28
28
  def failure_message
29
29
  expected_times_executed = @expected_times_executed || 1
30
- %Q(The request #{request_pattern.to_s} was expected to execute #{expected_times_executed} time#{ (expected_times_executed == 1) ? '' : 's'} but it executed #{times_executed} time#{ (times_executed == 1) ? '' : 's'})
30
+ text = %Q(The request #{request_pattern.to_s} was expected to execute #{times(expected_times_executed)} but it executed #{times(times_executed)})
31
+ text << self.class.executed_requests_message
32
+ text
31
33
  end
32
34
 
33
35
  def negative_failure_message
34
- if @expected_times_executed
35
- %Q(The request #{request_pattern.to_s} was not expected to execute #{expected_times_executed} time#{ (expected_times_executed == 1) ? '' : 's'} but it executed #{times_executed} time#{ (times_executed == 1) ? '' : 's'})
36
+ text = if @expected_times_executed
37
+ %Q(The request #{request_pattern.to_s} was not expected to execute #{times(expected_times_executed)} but it executed #{times(times_executed)})
36
38
  else
37
- %Q(The request #{request_pattern.to_s} was expected to execute 0 times but it executed #{times_executed} time#{ (times_executed == 1) ? '' : 's'})
39
+ %Q(The request #{request_pattern.to_s} was expected to execute 0 times but it executed #{times(times_executed)})
38
40
  end
41
+ text << self.class.executed_requests_message
42
+ text
43
+ end
44
+
45
+ def self.executed_requests_message
46
+ "\n\nThe following requests were made:\n\n#{RequestRegistry.instance.to_s}\n" + "="*60
47
+ end
48
+
49
+ private
50
+
51
+ def times(times)
52
+ "#{times} time#{ (times == 1) ? '' : 's'}"
39
53
  end
40
54
 
41
55
  end
@@ -167,7 +167,7 @@ module WebMock
167
167
  end
168
168
 
169
169
  def normalize_hash(hash)
170
- JSON.parse(JSON.generate(hash))
170
+ WebMock::Util::HashKeysStringifier.stringify_keys!(hash)
171
171
  end
172
172
 
173
173
  end
@@ -3,47 +3,32 @@ module WebMock
3
3
  class RequestRegistry
4
4
  include Singleton
5
5
 
6
- attr_accessor :request_stubs, :requested_signatures
6
+ attr_accessor :requested_signatures
7
7
 
8
8
  def initialize
9
- reset_webmock
9
+ reset!
10
10
  end
11
11
 
12
- def reset_webmock
13
- self.request_stubs = []
12
+ def reset!
14
13
  self.requested_signatures = Util::HashCounter.new
15
14
  end
16
15
 
17
- def register_request_stub(stub)
18
- request_stubs.insert(0, stub)
19
- stub
20
- end
21
-
22
- def registered_request?(request_signature)
23
- request_stub_for(request_signature)
24
- end
25
-
26
- def response_for_request(request_signature)
27
- stub = request_stub_for(request_signature)
28
- stub ? evaluate_response_for_request(stub.response, request_signature) : nil
29
- end
30
-
31
16
  def times_executed(request_pattern)
32
17
  self.requested_signatures.hash.select { |request_signature, times_executed|
33
18
  request_pattern.matches?(request_signature)
34
19
  }.inject(0) {|sum, (_, times_executed)| sum + times_executed }
35
20
  end
36
21
 
37
- private
38
-
39
- def request_stub_for(request_signature)
40
- request_stubs.detect { |registered_request_stub|
41
- registered_request_stub.request_pattern.matches?(request_signature)
42
- }
43
- end
44
-
45
- def evaluate_response_for_request(response, request_signature)
46
- response.evaluate(request_signature)
22
+ def to_s
23
+ if requested_signatures.hash.empty?
24
+ "No requests were made."
25
+ else
26
+ text = ""
27
+ self.requested_signatures.each do |request_signature, times_executed|
28
+ text << "#{request_signature} was made #{times_executed} time#{times_executed == 1 ? '' : 's' }\n"
29
+ end
30
+ text
31
+ end
47
32
  end
48
33
 
49
34
  end