webmock 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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