mockumentary 0.2.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.
@@ -0,0 +1,92 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "mockumentary"
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kane Baccigalupi"]
12
+ s.date = "2011-10-28"
13
+ s.description = " With the happy proliferation of TDD, test suites are getting massive, and developer efficiency is dwindling\n as we wait for our tests to pass. There is a big tradeoff between making unit test more integrationish (and therefore more reliable) vs.\n making them very mocky, unity and fast. Mockumentary is a library for the later. It inspects the ActiveRecord universe and\n makes a series of AR mockeries that approximate model without hitting the database, or making any assertions. The assertions,\n they are still part of the developers job.\n \n Mocumentary has two types of AR mockeries: One is used within the Rails universe. It uses introspection to derive association\n and field information. The second is a static copy built from the first. This static version can be used outside the Rails\n test universe in a suite faster than the speed of Rails environment load time.\n \n Mocking isn't for everyone, so test-drive responsibly.\n"
14
+ s.email = "baccigalupi@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "lib/mockumentary.rb",
29
+ "lib/mockumentary/active_record.rb",
30
+ "lib/mockumentary/collection.rb",
31
+ "lib/mockumentary/data.rb",
32
+ "lib/mockumentary/mockery.rb",
33
+ "lib/mockumentary/mocksimile.rb",
34
+ "lib/mockumentary/model.rb",
35
+ "mockumentary.gemspec",
36
+ "spec/fixtures/app/models/event.rb",
37
+ "spec/fixtures/app/models/event/follow.rb",
38
+ "spec/fixtures/app/models/event_resource.rb",
39
+ "spec/fixtures/app/models/task.rb",
40
+ "spec/fixtures/app/models/user.rb",
41
+ "spec/fixtures/config/.gitkeep",
42
+ "spec/fixtures/db/schema.rb",
43
+ "spec/mockery/active_record_spec.rb",
44
+ "spec/mockery/collection_spec.rb",
45
+ "spec/mockery/data_spec.rb",
46
+ "spec/mockery/mockery_spec.rb",
47
+ "spec/mockery/mockumentary_spec.rb",
48
+ "spec/mockery/spec_helper.rb",
49
+ "spec/mocksimile/mocksimile_spec.rb",
50
+ "spec/mocksimile/mockumentary_spec.rb",
51
+ "spec/mocksimile/spec_helper.rb"
52
+ ]
53
+ s.homepage = "http://github.com/baccigalupi/mockumentary"
54
+ s.licenses = ["MIT"]
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = "1.8.10"
57
+ s.summary = "An ActiveRecord mocking framework, for making your copius BDD rails tests not quite so slow"
58
+
59
+ if s.respond_to? :specification_version then
60
+ s.specification_version = 3
61
+
62
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
63
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
64
+ s.add_runtime_dependency(%q<hashie>, [">= 0"])
65
+ s.add_runtime_dependency(%q<faker>, [">= 0"])
66
+ s.add_development_dependency(%q<activerecord>, ["~> 3.1.1"])
67
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
68
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
69
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
70
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
71
+ else
72
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
73
+ s.add_dependency(%q<hashie>, [">= 0"])
74
+ s.add_dependency(%q<faker>, [">= 0"])
75
+ s.add_dependency(%q<activerecord>, ["~> 3.1.1"])
76
+ s.add_dependency(%q<sqlite3>, [">= 0"])
77
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
78
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
79
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
80
+ end
81
+ else
82
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
83
+ s.add_dependency(%q<hashie>, [">= 0"])
84
+ s.add_dependency(%q<faker>, [">= 0"])
85
+ s.add_dependency(%q<activerecord>, ["~> 3.1.1"])
86
+ s.add_dependency(%q<sqlite3>, [">= 0"])
87
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
88
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
89
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
90
+ end
91
+ end
92
+
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + "/../event"
2
+ class Event::Follow < Event
3
+ end
@@ -0,0 +1,4 @@
1
+ class Event < ActiveRecord::Base
2
+ belongs_to :actor, :class_name => 'User', :foreign_key => :user_id
3
+ has_many :event_resources
4
+ end
@@ -0,0 +1,27 @@
1
+ class EventResource < ActiveRecord::Base
2
+ belongs_to :event
3
+ belongs_to :user_resource, :class_name => 'User', :foreign_key => :resource_id
4
+ belongs_to :task_resource, :class_name => 'Task', :foreign_key => :resource_id
5
+
6
+ def user
7
+ user_resource if resource_type == 'User'
8
+ end
9
+
10
+ def task
11
+ task_resource if resource_type == 'Task'
12
+ end
13
+
14
+ def resource=(r)
15
+ if r.is_a?(User)
16
+ self.user_resource = r
17
+ else
18
+ self.task_resource = r
19
+ end
20
+ self.resource_type = r.class.to_s
21
+ r
22
+ end
23
+
24
+ def resource
25
+ user || task
26
+ end
27
+ end
@@ -0,0 +1,2 @@
1
+ class Task < ActiveRecord::Base
2
+ end
@@ -0,0 +1,9 @@
1
+ class User < ActiveRecord::Base
2
+ has_many :tasks
3
+ has_many :activities, :class_name => 'Event'
4
+ has_many :activity_references,
5
+ :class_name => 'EventResource',
6
+ :foreign_key => :resource_id,
7
+ :conditions => ['resource_type = ?', 'User']
8
+ has_many :events, :through => :activity_references, :source => :event
9
+ end
File without changes
@@ -0,0 +1,33 @@
1
+ ActiveRecord::Schema.define(:version => 20111020063332) do
2
+ create_table "event_resources", :force => true do |t|
3
+ t.integer "event_id"
4
+ t.string "type"
5
+ t.string "resource_type"
6
+ t.integer "resource_id"
7
+ t.datetime "created_at"
8
+ t.datetime "updated_at"
9
+ end
10
+
11
+ create_table "events", :force => true do |t|
12
+ t.integer "user_id"
13
+ t.string "type"
14
+ t.datetime "created_at"
15
+ t.datetime "updated_at"
16
+ end
17
+
18
+ create_table "tasks", :force => true do |t|
19
+ t.string "name"
20
+ t.datetime "due_at"
21
+ t.integer "priority"
22
+ t.integer "user_id"
23
+ t.datetime "created_at"
24
+ t.datetime "updated_at"
25
+ end
26
+
27
+ create_table "users", :force => true do |t|
28
+ t.string "name"
29
+ t.datetime "created_at"
30
+ t.datetime "updated_at"
31
+ end
32
+ end
33
+
@@ -0,0 +1,51 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class ActiveRecord::Base
4
+ extend Mockumentary::ActiveRecord
5
+ end
6
+
7
+ describe Mockumentary::ActiveRecord do
8
+ describe '.discover_mock_class' do
9
+ it 'is called by mock_class if no mock class is set' do
10
+ User.should_receive(:discover_mock_class!)
11
+ User.mock_class
12
+ end
13
+
14
+ it 'calls Mockumentary.generate if there are no matching mock classes' do
15
+ Mockery.should_receive(:generate).with(User)
16
+ Mockery.stub(:classes).and_return([])
17
+ User.instance_eval("@mock_class = nil")
18
+ User.mock_class
19
+ end
20
+
21
+ it 'finds the Mockery related to itself' do
22
+ User.mock_class.should == Mockery::User
23
+ end
24
+ end
25
+
26
+ describe 'mock methods' do
27
+ it '#mock calls #mock on the related AR class' do
28
+ mock_user = User.mock(:foo => 'bar')
29
+ mock_user.id.should be_nil
30
+ mock_user.new_record.should == true
31
+ mock_user.foo.should == 'bar'
32
+ mock_user.name.should be_a(String)
33
+ end
34
+
35
+ it '#mock! calls #mock! on the related AR class' do
36
+ mock_user = User.mock!(:bar => 'baz')
37
+ mock_user.id.should be_a(Fixnum)
38
+ mock_user.bar.should == 'baz'
39
+ mock_user.new_record.should be_false
40
+ mock_user.name.should be_a(String)
41
+ end
42
+
43
+ it '#mew calls #new on the related AR class' do
44
+ mock_user = User.mew(:baz => 'zardoz')
45
+ mock_user.baz.should == 'zardoz'
46
+ mock_user.new_record.should be_true
47
+ mock_user.name.should be_nil
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,96 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Mockumentary::Collection do
4
+ describe '::Collection' do
5
+ before do
6
+ Mockery.generate(User)
7
+ @collection = Mockumentary::Collection.new(Mockery::User)
8
+ end
9
+
10
+ it 'is enumerable' do
11
+ @collection.should be_a(Enumerable)
12
+ end
13
+
14
+ it 'starts out empty' do
15
+ @collection.should_not be_nil
16
+ @collection.should be_empty
17
+ end
18
+
19
+ it 'mock a collection of new objects of a particular type' do
20
+ @collection.mock(4).map(&:class).uniq.should == [Mockery::User]
21
+ @collection.size.should == 4
22
+ @collection.first.new_record?.should == true
23
+ @collection.first.name.should be_a(String)
24
+ end
25
+
26
+ it 'mock! will do the same but mock the saving too' do
27
+ @collection.mock!(2).map(&:new_record?).uniq.should == [false]
28
+ end
29
+
30
+ it '#build will mock an object into the collection' do
31
+ @collection.build(:name => 'proto awesomeness')
32
+ @collection.size.should == 1
33
+ @collection.first.name.should == 'proto awesomeness'
34
+ @collection.first.new_record?.should == true
35
+ end
36
+
37
+ it '#create will mock a saved object into the collection' do
38
+ @collection.create(:name => 'awesome saviness')
39
+ @collection.size.should == 1
40
+ @collection.first.name.should == 'awesome saviness'
41
+ @collection.first.new_record?.should == false
42
+ end
43
+
44
+ it '#create! will do the same as #create' do
45
+ @collection.create!(:name => 'awesome saviness')
46
+ @collection.size.should == 1
47
+ @collection.first.name.should == 'awesome saviness'
48
+ @collection.first.new_record?.should == false
49
+ end
50
+
51
+ it 'overrides the enum #delete to take in multiple records' do
52
+ @collection.mock(4)
53
+ first_two = @collection[0..1]
54
+ @collection.delete(*(first_two))
55
+ @collection.size.should == 2
56
+ @collection.map(&:id).should_not include(first_two.map(&:id))
57
+ end
58
+
59
+ it '#delete_all, #destroy_all, #reset all clear the collection' do
60
+ @collection.mock(2)
61
+ @collection.size.should == 2
62
+ @collection.delete_all
63
+ @collection.size.should == 0
64
+
65
+ @collection.mock(2)
66
+ @collection.size.should == 2
67
+ @collection.destroy_all
68
+ @collection.size.should == 0
69
+
70
+
71
+ @collection.mock(2)
72
+ @collection.size.should == 2
73
+ @collection.reset
74
+ @collection.size.should == 0
75
+ end
76
+
77
+ it '#exist? compares by id (which doesn\'t make sense if you aren\'t using mock!)' do
78
+ @collection.mock!(3)
79
+ @collection.exist?(@collection.first).should be_true
80
+ @collection.exist?(Mockery::User.mock!).should be_false
81
+ end
82
+ end
83
+ end
84
+
85
+ describe Mockery, 'collection mocking' do
86
+ before do
87
+ Mockery.generate(User)
88
+ @user = Mockery::User.mock
89
+ end
90
+
91
+ it 'should default to empty collections' do
92
+ user_tasks = @user.tasks
93
+ user_tasks.should be_a(Mockumentary::Collection)
94
+ user_tasks.should be_empty
95
+ end
96
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Mockumentary::Data do
4
+ it 'should generate data via methods' do
5
+ Mockumentary::Data.datetime.should be_a(Time)
6
+ Mockumentary::Data.full_name.should be_a(String)
7
+ Mockumentary::Data.full_name.split.size.should == 2
8
+ end
9
+
10
+ it 'should generate from the correct class given a key' do
11
+ name = Mockumentary::Data.generate(:full_name)
12
+ name.should be_a(String)
13
+ name.split.size.should == 2
14
+ end
15
+ end
@@ -0,0 +1,302 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Mockery do
4
+ describe 'basic behavior' do
5
+ before do
6
+ @model = Mockery.new
7
+ end
8
+
9
+ it 'will respond to any method without raising an error' do
10
+ @model.fooey_bar.should be_nil
11
+ end
12
+
13
+ it 'can be loaded with a hash of options' do
14
+ model = Mockery.new(:fooey_bar => 'zardoz')
15
+ model.fooey_bar.should == 'zardoz'
16
+ end
17
+
18
+ it 'attributes can be set on individual items' do
19
+ @model.fooey_bar = 'funktastic'
20
+ @model.fooey_bar.should == 'funktastic'
21
+ end
22
+ end
23
+
24
+ describe '.generate' do
25
+ before do
26
+ Mockery.generate(User)
27
+ end
28
+
29
+ it 'creates a class in the Mockery namespace' do
30
+ defined?(Mockery::User).should == 'constant'
31
+ end
32
+
33
+ it 'created class is a Mockery subclass' do
34
+ Mockery::User.ancestors.should include(Mockery)
35
+ end
36
+
37
+ it "should not re-evaluate the class desclaration if the class already exists" do
38
+ Mockumentary.should_not_receive(:class_eval)
39
+ Mockery.generate(User)
40
+ end
41
+
42
+ it 'should introspect on the created class' do
43
+ Mockery::User.mock_defaults.should == {:name => :string}
44
+ end
45
+ end
46
+
47
+ describe 'mocking' do
48
+ before do
49
+ Mockery.generate(Event)
50
+ Mockery.generate(User)
51
+ end
52
+
53
+ describe '.ar_class' do
54
+ it 'should be the AR class that it was constructed with' do
55
+ Mockery::User.ar_class.should == User
56
+ end
57
+
58
+ it 'setting it will cause introspection to occur' do
59
+ Mockery::User.ar_class = Event
60
+ Mockery::User.mock_defaults.should == Mockery::Event.mock_defaults
61
+ end
62
+
63
+ it 'can be inferred when it is nil' do
64
+ Mockery::User.ar_class = nil
65
+ Mockery::User.ar_class.should == User
66
+ end
67
+ end
68
+
69
+ describe '.new' do
70
+ it 'should not add any real attributes' do
71
+ user = Mockery::User.new
72
+ user.name.should be_nil
73
+ user.created_at.should be_nil
74
+ user.updated_at.should be_nil
75
+ user.id.should be_nil
76
+ end
77
+
78
+ it 'should be a new record' do
79
+ user = Mockery::User.new
80
+ user.new_record?.should be_true
81
+ end
82
+
83
+ it 'can receive options that it will set on the instance' do
84
+ user = Mockery::User.new(:name => 'foo bar')
85
+ user.name.should == 'foo bar'
86
+ end
87
+
88
+ it 'should have relationships' do
89
+ user = Mockery::User.new
90
+ user.event_resources.mock
91
+ user.event_resources.size.should == 1
92
+ user.event_resources.first.should be_a(Mockery::EventResource)
93
+ end
94
+ end
95
+
96
+ describe '.mock' do
97
+ before do
98
+ Mockery::User.ar_class = User
99
+ end
100
+
101
+ it 'should add faked attributes' do
102
+ user = Mockery::User.mock
103
+ user.name.should be_a(String)
104
+ user.name.split.size.should == 3
105
+ end
106
+
107
+ it 'should not add an id, or other save attributes' do
108
+ user = Mockery::User.mock
109
+ user.id.should be_nil
110
+ user.created_at.should be_nil
111
+ user.updated_at.should be_nil
112
+ end
113
+
114
+ it 'should be a new record' do
115
+ user = Mockery::User.mock
116
+ user.new_record?.should be_true
117
+ end
118
+
119
+ it 'should accept initialization options' do
120
+ user = Mockery::User.mock(:foo => 'bar')
121
+ user.foo.should == 'bar'
122
+ end
123
+ end
124
+
125
+ describe '.mock!' do
126
+ it 'should add faked attributes' do
127
+ user = Mockery::User.mock!
128
+ user.name.should be_a(String)
129
+ end
130
+
131
+ it 'should create an incrementing id' do
132
+ user = Mockery::User.mock!
133
+ user.id.should be_a(Fixnum)
134
+ Mockery::User.mock!.id.should == user.id + 1
135
+ end
136
+
137
+ it 'should build updated_at and created_at attributes' do
138
+ user = Mockery::User.mock!
139
+ user.created_at.should be_a(Time)
140
+ user.updated_at.should be_a(Time)
141
+ end
142
+
143
+ it 'should not be a new record' do
144
+ user = Mockery::User.mock!
145
+ user.new_record?.should be_false
146
+ end
147
+
148
+ it 'should allow overrides with initialization options' do
149
+ user = Mockery::User.mock!(:name => 'footy barf')
150
+ user.name.should == 'footy barf'
151
+ end
152
+ end
153
+ end
154
+
155
+ describe 'overriding defaults' do
156
+ before do
157
+ Mockery.generate(User)
158
+ end
159
+
160
+ describe 'with mock options' do
161
+ before do
162
+ class Mockery::User
163
+ def self.overrides
164
+ { :mock =>
165
+ {
166
+ :name => :full_name,
167
+ :foo => 'not bar'
168
+ }
169
+ }
170
+ end
171
+ end
172
+
173
+ @user = Mockery::User.mock(:foo => 'bar')
174
+ end
175
+
176
+ it 'should use the overrides instead of the defaults' do
177
+ @user.name.split.size.should == 2
178
+ end
179
+
180
+ it 'should not override initializaiton options' do
181
+ @user.foo.should == 'bar'
182
+ end
183
+ end
184
+
185
+ describe 'with init options' do
186
+ before do
187
+ class Mockery::User
188
+ def self.overrides
189
+ { :init =>
190
+ {
191
+ :state => 'new',
192
+ :new_record => 'yup'
193
+ }
194
+ }
195
+ end
196
+ end
197
+
198
+ @user = Mockery::User.new(:state => 'jaded')
199
+ end
200
+
201
+ it 'should use the overrieds instead of the defaults' do
202
+ @user.new_record.should == 'yup'
203
+ end
204
+
205
+ it 'should options passed into new over those on the class' do
206
+ @user.state.should == 'jaded'
207
+ end
208
+ end
209
+
210
+ describe 'save options' do
211
+ before do
212
+ class Mockery::User
213
+ def self.overrides
214
+ { :save =>
215
+ {
216
+ :state => 'saved',
217
+ :created_at => Time.now + 3.years
218
+ }
219
+ }
220
+ end
221
+ end
222
+
223
+ @user = Mockery::User.mock!(:state => 'jaded')
224
+ end
225
+
226
+ it 'should use the overrides instead of the defaults' do
227
+ @user.created_at.should > Time.now + 61.days
228
+ end
229
+
230
+ it 'should options passed into new over those on the class' do
231
+ @user.state.should == 'jaded'
232
+ end
233
+
234
+ it 'should override the initalization options' do
235
+ @user.new_record.should == false
236
+ end
237
+ end
238
+ end
239
+
240
+ describe '.dump' do
241
+ before do
242
+ Rails.stub(:root).and_return(FIXTURE_ROOT)
243
+ Mockumentary.introspect
244
+ @dir = "#{FIXTURE_ROOT}/config"
245
+ @path = @dir + "/mockumentary.yml"
246
+ File.delete(@path) if File.exist?(@path)
247
+
248
+ class Mockery::User
249
+ def self.overrides
250
+ {
251
+ :init => {:state => 'new'},
252
+ :mock => {:full_name => :full_name},
253
+ :save => {:state => 'saved'}
254
+ }
255
+ end
256
+ end
257
+
258
+ Mockery.dump
259
+ @hash = YAML.load(File.read(@path))
260
+ end
261
+
262
+ it 'will create a new file to the Rails.root config path' do
263
+ File.exist?(@path).should be_true
264
+ end
265
+
266
+ it 'will have an entry for each class' do
267
+ @hash.keys.should include 'User', 'Event', 'EventResource', 'Task', 'Event::Follow'
268
+ end
269
+
270
+ it 'each class will have an init hash that combines that classes overrides with init_defaults' do
271
+ @hash['User'][:init].should == {
272
+ :state => 'new',
273
+ :new_record => true
274
+ }
275
+ end
276
+
277
+ it 'each class will have a mock hash that combines overrieds with defaults' do
278
+ @hash['User'][:mock].should == {
279
+ :name => :string,
280
+ :full_name => :full_name
281
+ }
282
+ end
283
+
284
+ it 'each class will have a save hash that combines overrides with defaults' do
285
+ save_hash = @hash['User'][:save]
286
+ save_hash[:state].should == 'saved'
287
+ save_hash[:created_at].should == :datetime
288
+ save_hash[:updated_at].should == :datetime
289
+ save_hash[:new_record].should == false
290
+ save_hash[:id].should == :uid
291
+ end
292
+
293
+ it 'stores the relationships' do
294
+ @hash['User'][:relationships].should == {
295
+ :tasks => 'Task',
296
+ :activities => 'Event',
297
+ :activity_references => 'EventResource',
298
+ :events => 'Event'
299
+ }
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Mockumentary do
4
+ describe '.introspect' do
5
+ before do
6
+ Rails.stub(:root).and_return(FIXTURE_ROOT)
7
+
8
+ @classes = []
9
+ Mockery.stub(:generate) do |args|
10
+ @classes << args
11
+ end
12
+ end
13
+
14
+ it 'calls Mockery.generate for each of the first level active record objects found' do
15
+ Mockumentary.introspect
16
+ @classes.should include User, Event, EventResource, Task
17
+ end
18
+
19
+ it 'calls Mockery.generate on nested models' do
20
+ Mockumentary.introspect
21
+ @classes.should include Event::Follow
22
+ end
23
+ end
24
+ end