mock5 1.0.3 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76be219294f80c132aa6185e6968ada828583e65
4
- data.tar.gz: 57a45abc38b9aeda5e26ca5dba4b7bd574ce527f
3
+ metadata.gz: 5e3ff7dc93593a4f21dd450ed0874f436d1493c9
4
+ data.tar.gz: 1599500a3e285e92e7931b4e24ce5790d0f6bc25
5
5
  SHA512:
6
- metadata.gz: 9f03b77ad3a4b76c135eaf5a0b138099350861a8340d59b465d84e869bb07f9fd0925955b1aa98a4a76fdba5ee9937641237972980b5fd7f2d121b8257514b43
7
- data.tar.gz: 4b2548315b2f6f24e71a15f8c39f0c3052fe4ade33c26d8d92a80a5088c46f33b78b3e28ff99c320b168d5d554fc16e29a4a2a5cf6fcfe0194f17fbcfdf4577d
6
+ metadata.gz: 6e93dd71cc6c4b953de995bd642764b17298a0e24c16ea2ede62d7c56dc0f70c71ad3397d9c456c43384f74f5c0f4b5dff1c1268d7a67a85026360a3f55b0005
7
+ data.tar.gz: 961aa86904f8e5f6fd54007202f4f107f4301174e01a864c9d72d94e180d0c931042b068b9cd21012148daafc98972cef47bfc126a0306120ab480f97eb9b884
data/README.md CHANGED
@@ -1,33 +1,88 @@
1
1
  # Mock5
2
- [![Gem Version](https://img.shields.io/gem/v/mock5.svg)][gem]
3
- [![Build Status](https://img.shields.io/travis/rwz/mock5.svg)][travis]
4
- [![Code Climate](https://img.shields.io/codeclimate/github/rwz/mock5.svg)][codeclimate]
5
- [gem]: https://rubygems.org/gems/mock5
6
- [travis]: http://travis-ci.org/rwz/mock5
7
- [codeclimate]: https://codeclimate.com/github/rwz/mock5
2
+ [![Gem Version](https://img.shields.io/gem/v/mock5.svg)](https://rubygems.org/gems/mock5)
3
+ [![Build Status](https://img.shields.io/travis/rwz/mock5.svg)](http://travis-ci.org/rwz/mock5)
4
+ [![Code Climate](https://img.shields.io/codeclimate/github/rwz/mock5.svg)](https://codeclimate.com/github/rwz/mock5)
5
+ [![Inline docs](http://inch-pages.github.io/github/rwz/mock5.svg)](http://inch-pages.github.io/github/rwz/mock5)
8
6
 
9
- Mock5 allows to mock external APIs with simple Sinatra Rake apps.
7
+ Mock5 allows to mock external APIs with simple Sinatra Rack apps.
10
8
 
11
9
  ## Installation
12
10
 
13
- Add this line to your application's Gemfile:
11
+ This gem could be useful for testing, and maybe development purposes.
12
+ Add it to the relevant groups in your Gemfile.
14
13
 
15
- gem "mock5"
14
+ ```ruby
15
+ gem "mock5", groups: [:test, :development]
16
+ ```
16
17
 
17
- And then execute:
18
+ and run `bundle`.
18
19
 
19
- $ bundle
20
+ ## Usage
20
21
 
21
- Or install it yourself as:
22
+ ### mock
23
+ Use this method to describe API you're trying to mock.
22
24
 
23
- $ gem install mock5
25
+ ```ruby
26
+ weather_api = Mock5.mock("http://weather-api.com") do
27
+ get "/weather.json" do
28
+ MultiJson.dump(
29
+ location: "Philadelphia, PA",
30
+ temperature: "60F",
31
+ description: "Sunny"
32
+ )
33
+ end
34
+ end
35
+ ```
24
36
 
25
- ## Usage
37
+ ### mount
38
+ Use this method to enable API mocks you've defined previously.
26
39
 
27
40
  ```ruby
41
+ Mock5.mount weather_api, some_other_api
42
+ Net::HTTP.get("weather-api.com", "/weather.json") # => "{\"location\":...
43
+ ```
44
+
45
+ ### unmount
46
+ Unmounts passed APIs if thery were previously mounted
47
+
48
+ ```ruby
49
+ Mock5.unmount some_other_api # [, and_another_api... ]
50
+ ```
51
+
52
+ ### mounted_apis
53
+ This method returns a Set of all currently mounted APIs
54
+
55
+ ```ruby
56
+ Mock5.mounted_apis # => { weather_api }
57
+ Mock5.mount another_api
58
+ Mock5.mounted_apis # => { weather_api, another_api }
59
+ ```
60
+
61
+ ### with_mounted
62
+ Executes the block with all given APIs mounted, and then unmounts them.
63
+
64
+ ```ruby
65
+ Mock5.mounted_apis # => { other_api }
66
+ Mock5.with_mounted weather_api, other_api do
67
+ Mock5.mounted_apis # => { other_api, weather_api }
68
+ run_weather_api_test_suite!
69
+ end
70
+ Mock5.mounted_apis # => { other_api }
71
+ ```
72
+
73
+ ## Example
74
+
75
+ Say you're writing a nice wrapper around remote user management REST API.
76
+ You want your library to handle any unexpected situation aproppriately and
77
+ show a relevant error message, or schedule a retry some time later.
78
+
79
+ Obviously, you can't rely on a production API to test all these codepaths. You
80
+ probably want a way to emulate all these situations locally. Enter Mock5:
81
+
82
+ ```ruby
83
+ # user registers successfully
28
84
  SuccessfulRegistration = Mock5.mock("http://example.com") do
29
85
  post "/users" do
30
- # emulate successful registration
31
86
  MultiJson.dump(
32
87
  first_name: "Zapp",
33
88
  last_name: "Brannigan",
@@ -36,6 +91,7 @@ SuccessfulRegistration = Mock5.mock("http://example.com") do
36
91
  end
37
92
  end
38
93
 
94
+ # registration returns validation error
39
95
  UnsuccessfulRegistration = Mock5.mock("http://example.com") do
40
96
  post "/users" do
41
97
  halt 406, MultiJson.dump(
@@ -45,28 +101,58 @@ UnsuccessfulRegistration = Mock5.mock("http://example.com") do
45
101
  end
46
102
  end
47
103
 
48
- describe MyApi do
104
+ # remote api is down for some reason
105
+ RegistrationUnavailable = Mock5.mock("http://example.com") do
106
+ post "/users" do
107
+ halt 503, "Service Unavailable"
108
+ end
109
+ end
110
+
111
+ # remote api times takes long time to respond
112
+ RegistrationTimeout = Mock5.mock("http://example.com") do
113
+ post "/users" do
114
+ sleep 15
115
+ end
116
+ end
117
+
118
+ describe MyApiWrapper do
49
119
  describe "successfull" do
50
120
  around do |example|
51
- Mock5.with_mounted SuccessfulRegistration do
52
- example.call
53
- end
121
+ Mock5.with_mounted(SuccessfulRegistration, &example)
54
122
  end
55
123
 
56
124
  it "allows user registration" do
57
- expect{ MyApi.register_user }.not_to raise_error
125
+ expect{ MyApiWrapper.register_user }.not_to raise_error
58
126
  end
59
127
  end
60
128
 
61
129
  describe "validation errors" do
62
130
  around do |example|
63
- Mock5.with_mounted UnsuccessfulRegistration do
64
- example.call
65
- end
131
+ Mock5.with_mounted(UnsuccessfulRegistration, &example)
132
+ end
133
+
134
+ it "raises a valiation error" do
135
+ expect{ MyApiWrapper.register_user }.to raise_error(MyApiWrapper::ValidationError)
136
+ end
137
+ end
138
+
139
+ describe "service is unavailable" do
140
+ around do |example|
141
+ Mock5.with_mounted(RegistrationUnavailable, &example)
142
+ end
143
+
144
+ it "raises a ServiceUnavailable error" do
145
+ expect{ MyApiWrapper.register_user }.to raise_error(MyApiWrapper::ServiceUnavailable)
146
+ end
147
+ end
148
+
149
+ describe "timeout" do
150
+ around do |example|
151
+ Mock5.with_mounted(RegistrationTimeout, &example)
66
152
  end
67
153
 
68
- it "returns errors" do
69
- expect{ MyApi.register_user }.to raise_error(MyApi::ValidationError)
154
+ it "raises timeout error" do
155
+ expect{ MyApiWrapper.register_user }.to raise_error(Timeout::Error)
70
156
  end
71
157
  end
72
158
  end
@@ -2,35 +2,108 @@ require "mock5/version"
2
2
  require "mock5/api"
3
3
  require "set"
4
4
 
5
+ # The main module of the gem, exposing all API management methods.
6
+ # Can be included into class.
5
7
  module Mock5
6
8
  extend self
7
9
 
10
+ # Returns a set of currently mounted APIs
11
+ #
12
+ # @return [Set] a list of currently mounted APIs
8
13
  def mounted_apis
9
14
  @_mounted_apis ||= Set.new
10
15
  end
11
16
 
12
- def mock(*args, &block)
13
- Api.new(*args, &block)
17
+ # Generates a new API
18
+ #
19
+ # @example
20
+ # my_mock_api = Mock5.mock("http://example.com") do
21
+ # get "posts" do
22
+ # [
23
+ # {id: 1, body: "a posy body"},
24
+ # {id: 2, body: "another post body"}
25
+ # ].to_json
26
+ # end
27
+ #
28
+ # post "posts" do
29
+ # halt 201, "The post was created successfully"
30
+ # end
31
+ # end
32
+ #
33
+ # @param endpoint [String] a url of the API service endpoint to mock.
34
+ # Should only include hostname and schema.
35
+ #
36
+ # @yield a block to define behavior using Sinatra API
37
+ #
38
+ # @return [Mock5::Api] a mountable API object
39
+ def mock(endpoint=nil, &block)
40
+ Api.new(endpoint, &block)
14
41
  end
15
42
 
43
+ # Mounts given list of APIs. Returns a list of APIs that were actually
44
+ # mounted. The APIs that were already mounted when the method is called
45
+ # are not included in the return value.
46
+ #
47
+ # @param apis [Enum #to_set] a list of APIs to mount
48
+ #
49
+ # @return [Set] a list of APIs actually mounted
16
50
  def mount(*apis)
17
- (apis.to_set - mounted_apis).each do |api|
51
+ apis.to_set.subtract(mounted_apis).each do |api|
18
52
  mounted_apis.add api
19
53
  registry.register_request_stub api.request_stub
20
54
  end
21
55
  end
22
56
 
57
+ # Unmount given APIs. Returns only the list of APIs that were actually
58
+ # unmounted. If the API wasn't mounted when the method is called, it won't be
59
+ # included in the return value.
60
+ #
61
+ # @param apis [Enum #to_set] a list of APIs to unmount
62
+ #
63
+ # @return [Set] a list of APIs actually unmounted
23
64
  def unmount(*apis)
24
- (mounted_apis & apis).each do |api|
65
+ mounted_apis.intersection(apis).each do |api|
25
66
  mounted_apis.delete api
26
67
  registry.remove_request_stub api.request_stub
27
68
  end
28
69
  end
29
70
 
71
+ # Returns true if all given APIs are mounted. false otherwise.
72
+ #
73
+ # @param apis [Enum #to_set] a list of APIs to check
74
+ #
75
+ # @return [Boolean] true if all given APIs are mounted, false otherwise
30
76
  def mounted?(*apis)
31
77
  apis.to_set.subset?(mounted_apis)
32
78
  end
33
79
 
80
+ # Mounts a list of given APIs, executes block and then unmounts them back.
81
+ # Useful for wrapping around RSpec tests. It only unmounts APIs that were
82
+ # not mounted before. Any API that was mounted before the method was
83
+ # called remains mounted.
84
+ #
85
+ # @example
86
+ # my_api = Mock5.mock("http://example.com") do
87
+ # get "index.html" do
88
+ # "<h1>Hello world!</h1>"
89
+ # end
90
+ # end
91
+ #
92
+ # another_api = Mock5.mock("http://foobar.com") do
93
+ # get "hello/:what" do
94
+ # "<h1>Hello #{params["what"]}</h1>"
95
+ # end
96
+ # end
97
+ #
98
+ # Mock5.with_mounted my_api, another_api do
99
+ # Net::HTTP.get("example.com", "/index.html") # => "<h1>Hello world!</h1>"
100
+ # Net::HTTP.get("foobar.com", "/hello/bar") # => "<h1>Hello, bar</h1>"
101
+ # end
102
+ #
103
+ # @param apis [Enum #to_set] a list of APIs to mount before executing the
104
+ # block
105
+ #
106
+ # @yield the block to execute with given APIs being mounted
34
107
  def with_mounted(*apis)
35
108
  mounted = mount(*apis)
36
109
  yield
@@ -38,6 +111,9 @@ module Mock5
38
111
  unmount *mounted
39
112
  end
40
113
 
114
+ # Unmounts all currently mounted APIs and returns them
115
+ #
116
+ # @return [Set] a list of unmounted APIs
41
117
  def unmount_all!
42
118
  unmount *mounted_apis
43
119
  end
@@ -3,14 +3,46 @@ require "sinatra"
3
3
  require "webmock"
4
4
 
5
5
  module Mock5
6
+ # A class representing an API mock
6
7
  class Api
7
- attr_reader :endpoint, :app
8
8
 
9
+ # @return [Sinatra::Base] a Sinatra app mocking the API
10
+ attr_reader :app
11
+
12
+ # @return [Regexp] a regexp to match the API request urls
13
+ attr_reader :endpoint
14
+
15
+ # Returns an instance of +Mock5::Api+
16
+ #
17
+ # @example
18
+ # my_mock_api = Mock5::Api.new("http://example.com") do
19
+ # get "posts" do
20
+ # [
21
+ # {id: 1, body: "a posy body"},
22
+ # {id: 2, body: "another post body"}
23
+ # ].to_json
24
+ # end
25
+ #
26
+ # post "posts" do
27
+ # halt 201, "The post was created successfully"
28
+ # end
29
+ # end
30
+ #
31
+ # @param endpoint [String, Regexp] a url of the API service to
32
+ # endpoint to mock. Can only contain schema and hostname, path
33
+ # should be empty.
34
+ #
35
+ # @yield a block passed to Sinatra to initialize an app
36
+ #
37
+ # @return [Mock5::Api]
9
38
  def initialize(endpoint=nil, &block)
10
39
  @app = Sinatra.new(&block)
11
40
  @endpoint = normalize_endpoint(endpoint)
12
41
  end
13
42
 
43
+ # Returns webmock request stub built with Sinatra app and enpoint url
44
+ #
45
+ # @return [WebMock::RequestStub]
14
46
  def request_stub
15
47
  @request_stub ||= WebMock::RequestStub.new(:any, endpoint).tap{ |s| s.to_rack(app) }
16
48
  end
@@ -1,3 +1,3 @@
1
1
  module Mock5
2
- VERSION = "1.0.3".freeze
2
+ VERSION = "1.0.5".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mock5
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Pravosud
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-13 00:00:00.000000000 Z
11
+ date: 2014-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: webmock
@@ -84,3 +84,4 @@ summary: Mock APIs using Sinatra
84
84
  test_files:
85
85
  - spec/mock5_api_spec.rb
86
86
  - spec/mock5_spec.rb
87
+ has_rdoc: