rspec-rails-mocha 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
- require 'spec'
1
+ require 'rspec/core'
2
2
  require 'rspec/rails/mocha'
3
3
 
4
- Spec::Runner.configure do |config|
4
+ RSpec.configure do |config|
5
5
  config.mock_with :mocha
6
- config.include Spec::Rails::Mocha
6
+ config.include RSpec::Rails::Mocha
7
7
  end
@@ -1,139 +1,207 @@
1
- # copied from rspec-rails v1.3 and tweaked to work as expected with Mocha
2
- # TODO: update to reflect the API of rspec-rails 2.0
3
- module Spec
1
+ require 'active_model'
2
+
3
+ module RSpec
4
4
  module Rails
5
- unless defined?(IllegalDataAccessException)
6
- class IllegalDataAccessException < StandardError; end
7
- end
8
-
9
5
  module Mocha
10
- # Creates a mock object instance for a +model_class+ with common
11
- # methods stubbed out. Additional methods may be easily stubbed (via
12
- # add_stubs) if +stubs+ is passed.
13
- def mock_model(model_class, options_and_stubs = {})
14
- id = options_and_stubs[:id] || next_id
15
- options_and_stubs = options_and_stubs.reverse_merge({
16
- :id => id,
17
- :to_param => id.to_s,
18
- :new_record? => false,
19
- :errors => stub("errors", :count => 0)
20
- })
21
- m = stub("#{model_class.name}_#{id}", options_and_stubs)
22
- m.instance_eval <<-CODE
23
- def as_new_record
24
- self.stubs(:id).returns(nil)
25
- self.stubs(:to_param).returns(nil)
26
- self.stubs(:new_record?).returns(true)
27
- self
28
- end
29
- def is_a?(other)
30
- #{model_class}.ancestors.include?(other)
31
- end
32
- def kind_of?(other)
33
- #{model_class}.ancestors.include?(other)
34
- end
35
- def instance_of?(other)
36
- other == #{model_class}
37
- end
38
- def class
39
- #{model_class}
40
- end
41
- CODE
42
- yield m if block_given?
43
- m
6
+ module ActiveModelInstanceMethods
7
+ def as_new_record
8
+ self.stubs(:persisted?) { false }
9
+ self.stubs(:id) { nil }
10
+ self
11
+ end
12
+
13
+ def persisted?
14
+ true
15
+ end
16
+
17
+ def respond_to?(message, include_private=false)
18
+ message.to_s =~ /_before_type_cast$/ ? false : super
19
+ end
44
20
  end
45
-
46
- module ModelStubber
47
- def connection
48
- raise IllegalDataAccessException.new("stubbed models are not allowed to access the database")
21
+
22
+ module ActiveRecordInstanceMethods
23
+ def destroy
24
+ self.stubs(:persisted?) { false }
25
+ self.stubs(:id) { nil }
49
26
  end
27
+
50
28
  def new_record?
51
- id.nil?
29
+ !persisted?
30
+ end
31
+ end
32
+
33
+ # Creates a test double representing +string_or_model_class+ with common
34
+ # ActiveModel methods stubbed out. Additional methods may be easily
35
+ # stubbed (via add_stubs) if +stubs+ is passed. This is most useful for
36
+ # impersonating models that don't exist yet.
37
+ #
38
+ # NOTE that only ActiveModel's methods, plus <tt>new_record?</tt>, are
39
+ # stubbed out implicitly. <tt>new_record?</tt> returns the inverse of
40
+ # <tt>persisted?</tt>, and is present only for compatibility with
41
+ # extension frameworks that have yet to update themselves to the
42
+ # ActiveModel API (which declares <tt>persisted?</tt>, not
43
+ # <tt>new_record?</tt>).
44
+ #
45
+ # +string_or_model_class+ can be any of:
46
+ #
47
+ # * A String representing a Class that does not exist
48
+ # * A String representing a Class that extends ActiveModel::Naming
49
+ # * A Class that extends ActiveModel::Naming
50
+ def mock_model(string_or_model_class, stubs = {})
51
+ if String === string_or_model_class
52
+ if Object.const_defined?(string_or_model_class)
53
+ model_class = Object.const_get(string_or_model_class)
54
+ else
55
+ model_class = Object.const_set(string_or_model_class, Class.new do
56
+ extend ActiveModel::Naming
57
+ end)
58
+ end
59
+ else
60
+ model_class = string_or_model_class
61
+ end
62
+
63
+ unless model_class.kind_of? ActiveModel::Naming
64
+ raise ArgumentError.new <<-EOM
65
+ The mock_model method can only accept as its first argument:
66
+ * A String representing a Class that does not exist
67
+ * A String representing a Class that extends ActiveModel::Naming
68
+ * A Class that extends ActiveModel::Naming
69
+
70
+ It received #{model_class.inspect}
71
+ EOM
72
+ end
73
+
74
+ stubs = stubs.reverse_merge(:id => next_id)
75
+ stubs = stubs.reverse_merge(:persisted? => !!stubs[:id])
76
+ stubs = stubs.reverse_merge(:destroyed? => false)
77
+ stubs = stubs.reverse_merge(:marked_for_destruction? => false)
78
+ stubs = stubs.reverse_merge(:errors => stub("errors", :count => 0, :[] => [], :empty? => true))
79
+
80
+ stub("#{model_class.name}_#{stubs[:id]}", stubs).tap do |m|
81
+ m.extend ActiveModelInstanceMethods
82
+ model_class.__send__ :include, ActiveModel::Conversion
83
+ model_class.__send__ :include, ActiveModel::Validations
84
+ if defined?(ActiveRecord)
85
+ m.extend ActiveRecordInstanceMethods
86
+ [:save, :update_attributes].each do |key|
87
+ if stubs[key] == false
88
+ m.errors.stubs(:empty?) { false }
89
+ end
90
+ end
91
+ end
92
+ m.instance_eval(<<-CODE, __FILE__, __LINE__)
93
+ def is_a?(other)
94
+ #{model_class}.ancestors.include?(other)
95
+ end
96
+ def kind_of?(other)
97
+ #{model_class}.ancestors.include?(other)
98
+ end
99
+ def instance_of?(other)
100
+ other == #{model_class}
101
+ end
102
+ def respond_to?(method_name, include_private=false)
103
+ #{model_class}.respond_to?(:column_names) && #{model_class}.column_names.include?(method_name.to_s) || super
104
+ end
105
+ def class
106
+ #{model_class}
107
+ end
108
+ def to_s
109
+ "#{model_class.name}_#{to_param}"
110
+ end
111
+
112
+ def to_key
113
+ [id]
114
+ end
115
+ CODE
116
+ yield m if block_given?
52
117
  end
118
+ end
119
+
120
+ module ActiveModelStubExtensions
53
121
  def as_new_record
54
- self.id = nil
122
+ self.stubs(:persisted?) { false }
123
+ self.stubs(:id) { nil }
55
124
  self
56
125
  end
57
126
  end
58
127
 
128
+ module ActiveRecordStubExtensions
129
+ def as_new_record
130
+ self.__send__("#{self.class.primary_key}=", nil)
131
+ super
132
+ end
133
+
134
+ def new_record?
135
+ !persisted?
136
+ end
137
+
138
+ def connection
139
+ raise RSpec::Rails::IllegalDataAccessException.new("stubbed models are not allowed to access the database")
140
+ end
141
+ end
142
+
59
143
  # :call-seq:
60
144
  # stub_model(Model)
61
145
  # stub_model(Model).as_new_record
62
146
  # stub_model(Model, hash_of_stubs)
63
147
  # stub_model(Model, instance_variable_name, hash_of_stubs)
64
148
  #
65
- # Creates an instance of +Model+ that is prohibited from accessing the
66
- # database*. For each key in +hash_of_stubs+, if the model has a
67
- # matching attribute (determined by asking it) are simply assigned the
68
- # submitted values. If the model does not have a matching attribute, the
69
- # key/value pair is assigned as a stub return value using RSpec's
70
- # mocking/stubbing framework.
149
+ # Creates an instance of +Model+ with +to_param+ stubbed using a
150
+ # generated value that is unique to each object.. If +Model+ is an
151
+ # +ActiveRecord+ model, it is prohibited from accessing the database*.
152
+ #
153
+ # For each key in +hash_of_stubs+, if the model has a matching attribute
154
+ # (determined by asking it) are simply assigned the submitted values. If
155
+ # the model does not have a matching attribute, the key/value pair is
156
+ # assigned as a stub return value using RSpec's mocking/stubbing
157
+ # framework.
71
158
  #
72
- # <tt>new_record?</tt> is overridden to return the result of id.nil?
73
- # This means that by default new_record? will return false. If you want
159
+ # <tt>persisted?</tt> is overridden to return the result of !id.nil?
160
+ # This means that by default persisted? will return true. If you want
74
161
  # the object to behave as a new record, sending it +as_new_record+ will
75
162
  # set the id to nil. You can also explicitly set :id => nil, in which
76
- # case new_record? will return true, but using +as_new_record+ makes the
163
+ # case persisted? will return false, but using +as_new_record+ makes the
77
164
  # example a bit more descriptive.
78
165
  #
79
166
  # While you can use stub_model in any example (model, view, controller,
80
167
  # helper), it is especially useful in view examples, which are
81
168
  # inherently more state-based than interaction-based.
82
169
  #
83
- # == Database Independence
84
- #
85
- # +stub_model+ does not make your examples entirely
86
- # database-independent. It does not stop the model class itself from
87
- # loading up its columns from the database. It just prevents data access
88
- # from the object itself. To completely decouple from the database, take
89
- # a look at libraries like unit_record or NullDB.
90
- #
91
170
  # == Examples
92
171
  #
93
172
  # stub_model(Person)
94
173
  # stub_model(Person).as_new_record
95
- # stub_model(Person, :id => 37)
174
+ # stub_model(Person, :to_param => 37)
96
175
  # stub_model(Person) do |person|
97
176
  # person.first_name = "David"
98
177
  # end
99
178
  def stub_model(model_class, stubs={})
100
- stubs = {:id => next_id}.merge(stubs)
101
- model_class.new.tap do |model|
102
- model.id = stubs.delete(:id)
103
- model.extend ModelStubber
179
+ model_class.new.tap do |m|
180
+ m.extend ActiveModelStubExtensions
181
+ if defined?(ActiveRecord) && model_class < ActiveRecord::Base
182
+ m.extend ActiveRecordStubExtensions
183
+ primary_key = model_class.primary_key.to_sym
184
+ stubs = stubs.reverse_merge(primary_key => next_id)
185
+ stubs = stubs.reverse_merge(:persisted? => !!stubs[primary_key])
186
+ else
187
+ stubs = stubs.reverse_merge(:id => next_id)
188
+ stubs = stubs.reverse_merge(:persisted? => !!stubs[:id])
189
+ end
104
190
  stubs.each do |k,v|
105
- if model.has_attribute?(k)
106
- model[k] = stubs.delete(k)
107
- end
191
+ m.__send__("#{k}=", stubs.delete(k)) if m.respond_to?("#{k}=")
108
192
  end
109
- model.stubs(stubs)
110
- yield model if block_given?
193
+ m.stubs(stubs)
194
+ yield m if block_given?
111
195
  end
112
196
  end
113
-
114
- # DEPRECATED - use object.stubs(:method => value, :method2 => value)
115
- #
116
- # Stubs methods on +object+ (if +object+ is a symbol or string a new mock
117
- # with that name will be created). +stubs+ is a Hash of +method=>value+
118
- def add_stubs(object, stubs = {}) #:nodoc:
119
- Kernel.warn <<-WARNING
120
- DEPRECATION NOTICE: add_stubs is deprecated and will be removed
121
- from a future version of rspec-rails. Use this instead:
122
-
123
- object.stubs(:method => value, :method2 => value)
124
-
125
- WARNING
126
- object.stubs(stubs)
127
- end
128
197
 
129
- private
198
+ private
130
199
 
131
- @@model_id = 1000
132
-
133
- def next_id
134
- @@model_id += 1
135
- end
200
+ @@model_id = 1000
136
201
 
202
+ def next_id
203
+ @@model_id += 1
204
+ end
137
205
  end
138
206
  end
139
207
  end
@@ -1,8 +1,25 @@
1
- require 'spec/autorun'
1
+ require 'rspec'
2
2
  require 'rspec-rails-mocha'
3
- require 'active_support/core_ext'
4
3
 
5
- class Person
4
+ # Simple stub for ActiveRecord::Base
5
+ module ActiveRecord
6
+ class Base
7
+ extend ActiveModel::Naming
8
+ class << self
9
+ def primary_key; "id"; end
10
+ end
11
+ end
12
+ end
13
+
14
+ module RSpec::Rails
15
+ # usually defined in "rspec/rails/mocks"
16
+ class IllegalDataAccessException < StandardError; end
17
+ end
18
+
19
+ require 'active_support/core_ext/hash/reverse_merge'
20
+ require 'active_support/core_ext/object'
21
+
22
+ class Person < ActiveRecord::Base
6
23
  attr_accessor :id, :name
7
24
 
8
25
  def has_attribute?(attr)
@@ -42,6 +59,13 @@ describe "rspec-rails Mocha plugin" do
42
59
  person.id.should == 66
43
60
  end
44
61
 
62
+ it "should use given ID in to_key" do
63
+ personA = create(Person, :id => 66)
64
+ personA.to_key.should == [66]
65
+ personB = create(Person)
66
+ personB.to_key.first.should >= 1000
67
+ end
68
+
45
69
  it "should mock a record with properties" do
46
70
  hacker = create(Hacker, :name => "Mislav", :skillz => 1337)
47
71
  hacker.name.should == "Mislav"
@@ -66,6 +90,8 @@ describe "rspec-rails Mocha plugin" do
66
90
 
67
91
  it "should have no errors" do
68
92
  create(Person).errors.count.should == 0
93
+ create(Person).errors.empty?.should be_true
94
+ create(Person).errors[:name].should == []
69
95
  end
70
96
  end
71
97
 
@@ -79,8 +105,8 @@ describe "rspec-rails Mocha plugin" do
79
105
  it "can't connect" do
80
106
  lambda {
81
107
  create(Person).connection
82
- }.should raise_error(Spec::Rails::IllegalDataAccessException)
108
+ }.should raise_error(RSpec::Rails::IllegalDataAccessException)
83
109
  end
84
110
  end
85
111
 
86
- end
112
+ end
metadata CHANGED
@@ -5,17 +5,18 @@ version: !ruby/object:Gem::Version
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 2
10
- version: 0.2.2
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Mislav Marohni\xC4\x87"
14
+ - Paul Rosania
14
15
  autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2011-02-20 00:00:00 +01:00
19
+ date: 2011-02-13 00:00:00 +01:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
@@ -42,12 +43,12 @@ dependencies:
42
43
  requirements:
43
44
  - - ">="
44
45
  - !ruby/object:Gem::Version
45
- hash: 31
46
+ hash: 15
46
47
  segments:
47
- - 1
48
- - 3
49
48
  - 2
50
- version: 1.3.2
49
+ - 0
50
+ - 0
51
+ version: 2.0.0
51
52
  type: :runtime
52
53
  version_requirements: *id002
53
54
  description: Ports functionality of mock_model and stub_model from rspec-rails using Mocha.