frenetic 0.0.20.alpha.4 → 0.0.20.alpha.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -402,6 +402,43 @@ end
402
402
  As you can see, this allows you to supply some default values for the attributes
403
403
  of your resource to ease object creation in testing.
404
404
 
405
+
406
+
407
+ ### Integration Testing
408
+
409
+ When it comes time to write integration tests for your API client, you can either
410
+ stub out all of the HTTP requests with something like WebMock or VCR, or you can
411
+ use Frenetic in `test_mode`
412
+
413
+ ```ruby
414
+ Frenetic.new( url:url, test_mode:true )
415
+ # ...or...
416
+ api = Frenetic.new(url:url)
417
+ api.config.test_mode = true
418
+ ```
419
+
420
+ Doing so will allow `Frenetic::Resource.find` to return a mock resource instead
421
+ of querying your API for what is available.
422
+
423
+ Example:
424
+
425
+ ```ruby
426
+ class MyResource < Frenetic::Resource
427
+ api_client { Frenetic.new(url) }
428
+ end
429
+
430
+ class MyMockResource < MyResource
431
+ include Frenetic::ResourceMockery
432
+ end
433
+
434
+ > MyResource.api_client.config.test_mode = true
435
+ # true
436
+ > MyResource.find(99)
437
+ # <MyMockResource id=99>
438
+ ```
439
+
440
+
441
+
405
442
  ## Contributing
406
443
 
407
444
  1. Fork it
@@ -5,15 +5,19 @@ class Frenetic
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- def find( params = {} )
8
+ def find( params )
9
9
  params = { id:params } unless params.is_a? Hash
10
10
 
11
+ return as_mock(params) if test_mode?
12
+
11
13
  if response = api.get( member_url(params) ) and response.success?
12
14
  new response.body
13
15
  end
14
16
  end
15
17
 
16
18
  def all
19
+ return [] if test_mode?
20
+
17
21
  if response = api.get( collection_url ) and response.success?
18
22
  Frenetic::ResourceCollection.new self, response.body
19
23
  end
@@ -1,7 +1,15 @@
1
1
  require 'ostruct'
2
+ require 'active_support/concern'
2
3
 
3
4
  class Frenetic
4
5
  module ResourceMockery
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # I'm sure this violates some sort of CS principle or best practice,
10
+ # but it solves the problem for now.
11
+ superclass.send :instance_variable_set, '@mock_class', self
12
+ end
5
13
 
6
14
  def attributes
7
15
  @params
@@ -32,6 +32,7 @@ class Frenetic
32
32
  headers: headers,
33
33
  password: password,
34
34
  ssl: ssl,
35
+ test_mode: test_mode,
35
36
  url: url,
36
37
  username: username
37
38
  }
@@ -71,6 +72,10 @@ class Frenetic
71
72
  @_cfg[:ssl] || { verify:true }
72
73
  end
73
74
 
75
+ def test_mode
76
+ @_cfg[:test_mode] || false
77
+ end
78
+
74
79
  def url
75
80
  Addressable::URI.parse @_cfg[:url]
76
81
  end
@@ -46,6 +46,14 @@ class Frenetic
46
46
  (api.schema[namespace]||{})['properties'] or raise HypermediaError, %Q{Could not find schema definition for the resource "#{namespace}"}
47
47
  end
48
48
 
49
+ def self.as_mock( params = {} )
50
+ raise Frenetic::ClientError, "Mock resource not defined for #{namespace}." \
51
+ " Subclass #{self} and mixin Frenetic::ResourceMockery" \
52
+ " to define a mock" unless @mock_class
53
+
54
+ @mock_class.new params
55
+ end
56
+
49
57
  def initialize( p = {} )
50
58
  build_params p
51
59
  @attrs = {}
@@ -112,5 +120,9 @@ class Frenetic
112
120
  self.class.properties
113
121
  end
114
122
 
123
+ def self.test_mode?
124
+ api_client.config.test_mode
125
+ end
126
+
115
127
  end
116
128
  end
@@ -1,3 +1,3 @@
1
1
  class Frenetic
2
- VERSION = '0.0.20.alpha.4'
2
+ VERSION = '0.0.20.alpha.5'
3
3
  end
@@ -45,6 +45,20 @@ describe Frenetic::MemberRestMethods do
45
45
  expect{ subject }.to raise_error Frenetic::ClientError
46
46
  end
47
47
  end
48
+
49
+ context 'in test mode' do
50
+ let(:test_cfg) { { url:'http://example.com/api', test_mode:true } }
51
+
52
+ before do
53
+ stub_const 'MyMockResource', Class.new(MyTempResource)
54
+
55
+ MyMockResource.send :include, Frenetic::ResourceMockery
56
+ end
57
+
58
+ it 'should return a mock resource' do
59
+ expect(subject).to be_an_instance_of MyMockResource
60
+ end
61
+ end
48
62
  end
49
63
 
50
64
  describe '.all' do
@@ -63,5 +77,13 @@ describe Frenetic::MemberRestMethods do
63
77
  expect(subject.first).to be_an_instance_of MyTempResource
64
78
  end
65
79
  end
80
+
81
+ context 'in test mode' do
82
+ let(:test_cfg) { { url:'http://example.com/api', test_mode:true } }
83
+
84
+ it 'should return an empty collection' do
85
+ expect(subject).to be_empty
86
+ end
87
+ end
66
88
  end
67
89
  end
@@ -3,8 +3,12 @@ require 'spec_helper'
3
3
  require 'frenetic/resource_mockery'
4
4
 
5
5
  describe Frenetic::ResourceMockery do
6
+ let(:my_temp_resource) do
7
+ Class.new(Frenetic::Resource)
8
+ end
9
+
6
10
  let(:my_mocked_resource) do
7
- Class.new(Frenetic::Resource) do
11
+ Class.new(my_temp_resource) do
8
12
  def default_attributes
9
13
  { qux:'qux' }
10
14
  end
@@ -21,6 +25,10 @@ describe Frenetic::ResourceMockery do
21
25
 
22
26
  subject { MyNamespace::MyMockedResource.new params }
23
27
 
28
+ it 'should violate some basic CS principles by telling the parent-class of its existence' do
29
+ expect(my_temp_resource.instance_variables).to include :@mock_class
30
+ end
31
+
24
32
  describe '#properties' do
25
33
  subject { super().properties }
26
34
 
@@ -19,6 +19,7 @@ describe Frenetic::Configuration do
19
19
  it { should include :headers }
20
20
  it { should include :password }
21
21
  it { should include :ssl }
22
+ it { should include :test_mode }
22
23
  it { should include :url }
23
24
  it { should include :username }
24
25
  end
@@ -101,6 +102,12 @@ describe Frenetic::Configuration do
101
102
  it { should include verify:true }
102
103
  end
103
104
 
105
+ describe '#test_mode' do
106
+ subject { instance.test_mode }
107
+
108
+ it { should be_false }
109
+ end
110
+
104
111
  describe '#url' do
105
112
  let(:cfg) do
106
113
  { url:'http://example.org' }
@@ -152,6 +152,32 @@ describe Frenetic::Resource do
152
152
  end
153
153
  end
154
154
 
155
+ describe '.as_mock' do
156
+ subject { MyNamespace::MyTempResource.as_mock id:99 }
157
+
158
+ context 'without a defined Mock-class' do
159
+ it 'should raise an error' do
160
+ expect{subject}.to raise_error Frenetic::ClientError
161
+ end
162
+ end
163
+
164
+ context 'with a defined Mock-class' do
165
+ before do
166
+ stub_const 'MyNamespace::MyMockResource', Class.new(MyNamespace::MyTempResource)
167
+
168
+ MyNamespace::MyMockResource.send :include, Frenetic::ResourceMockery
169
+ end
170
+
171
+ it 'should return a mock instance of the resource' do
172
+ expect(subject).to be_an_instance_of MyNamespace::MyMockResource
173
+ end
174
+
175
+ it 'should initialize the mock with the provided values' do
176
+ expect(subject.id).to eq 99
177
+ end
178
+ end
179
+ end
180
+
155
181
  describe '#initialize' do
156
182
  before { @stubs.api_description }
157
183
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frenetic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.20.alpha.4
4
+ version: 0.0.20.alpha.5
5
5
  prerelease: 7
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-15 00:00:00.000000000 Z
12
+ date: 2013-05-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -215,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
215
215
  version: '0'
216
216
  segments:
217
217
  - 0
218
- hash: -3576003086095464905
218
+ hash: -3382151532624258123
219
219
  required_rubygems_version: !ruby/object:Gem::Requirement
220
220
  none: false
221
221
  requirements: