model_mocker 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Matt Patterson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,38 @@
1
+ = ModelMocker
2
+
3
+ This plugin gives you an easy way of generating partially mocked ActiveRecord model objects. This is a useful way of simulating some aspects of a model (like the persistence layer) but leaving the domain logic parts intact, so that you test those in isolation, without worry about database reads and writes.
4
+
5
+ It's similar to RSpec's mock_model method, but gives you a slightly more declarative way of going about things. I found myself wanting something along these lines a long time ago, and created something very simple that I've used in several projects. More recently I've found myself wanting to easily control certain kinds of behaviour in controller specs, like wanting to ensure that a model instance is valid to allow easy and declarative speccing of the controller.
6
+
7
+ The plugin adds a <tt>mock</tt> method to <tt>ActiveRecord::Base</tt> when <tt>mock_models</tt> is required, which behaves a lot like <tt>AR::Base.new</tt> or <tt>AR::Base.create</tt>, except that you can specify an ID too. Special behaviour is added by passing a block to <tt>mock</tt> and calling methods on the object it yields.
8
+
9
+ == Installation
10
+
11
+ For Rails 2, add <tt>model_mocker</tt> to your <tt>config.gem</tt> for the test evironment.
12
+
13
+ For Rails 3, add <tt>model_mocker</tt> to your +Gemfile+ in the <tt>:test</tt> group.
14
+
15
+ == Requirements
16
+
17
+ ModelMocker uses the Mocha[http://mocha.rubyforge.org/] Gem.
18
+
19
+ == Examples
20
+
21
+ To create a mocked model instance which behaves as it's been fetched from the DB:
22
+
23
+ ModelClass.mock(:id => 1)
24
+
25
+ To create one which behaves as if it's a new record
26
+
27
+ ModelClass.mock { |m| m.as_new_record }
28
+
29
+ One which is new and will always report that is invalid, whether or not ActiveRecord validations have been met or not.
30
+
31
+ ModelClass.mock do |m|
32
+ m.as_new_record
33
+ m.invalid
34
+ end
35
+
36
+ The RDoc for the instance methods on ModelMocker gives a complete rundown of what's possible.
37
+
38
+ Copyright (c) 2008 Matt Patterson, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ rspec_base = File.expand_path(File.dirname(__FILE__) + '/../rspec/lib')
4
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
5
+ require 'spec/rake/spectask'
6
+
7
+ desc 'Default: run specs.'
8
+ task :default => :spec
9
+
10
+ desc 'Generate documentation for the model_mocker plugin.'
11
+ Rake::RDocTask.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'doc/rdoc'
13
+ rdoc.title = 'ModelMocker'
14
+ rdoc.options << '--line-numbers' << '--inline-source' #<< '--main' << 'ModelMocker'
15
+ rdoc.rdoc_files.include('README.rdoc')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ task :stats => "spec:statsetup"
20
+
21
+ desc "Run all specs in spec directory"
22
+ Spec::Rake::SpecTask.new(:spec) do |t|
23
+ t.spec_opts = ['--options', "spec/spec.opts"]
24
+ t.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ namespace :spec do
28
+ desc "Run all specs in spec directory with RCov"
29
+ Spec::Rake::SpecTask.new(:rcov) do |t|
30
+ t.spec_opts = ['--options', "spec/spec.opts"]
31
+ t.spec_files = FileList['spec/**/*_spec.rb']
32
+ t.rcov = true
33
+ t.rcov_opts = lambda do
34
+ IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
35
+ end
36
+ end
37
+
38
+ desc "Print Specdoc for all specs (excluding plugin specs)"
39
+ Spec::Rake::SpecTask.new(:doc) do |t|
40
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
41
+ t.spec_files = FileList['spec/**/*_spec.rb']
42
+ end
43
+
44
+ # Setup specs for stats
45
+ task :statsetup do
46
+ require 'code_statistics'
47
+ ::STATS_DIRECTORIES << %w(All\ specs spec)
48
+ ::CodeStatistics::TEST_TYPES << "All specs"
49
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
50
+ end
51
+ end
@@ -0,0 +1,120 @@
1
+ require 'mocha'
2
+
3
+ # class ActiveRecord::Base
4
+ # # Create a new instance of the class, pass in creation params and then
5
+ # # yield the ModelMocker instance so that methods can be called on it
6
+ # def self.mock(params = {})
7
+ # mock_model = ModelMocker.new(self, params)
8
+ # yield(mock_model) if block_given?
9
+ # mock_model.instance
10
+ # end
11
+ # end
12
+
13
+ # An easy way of generating partially mocked <tt>ActiveRecord</tt> model objects.
14
+ # This is a useful way of simulating some aspects of a model (like the
15
+ # persistence layer) but leaving the domain logic parts intact, so that
16
+ # you can test those in isolation, without worrying about database reads
17
+ # and writes.
18
+ class ModelMocker
19
+ # Provides instance method replacements for the <tt>ActiveRecord::Base</tt> instances created by <tt>#mock</tt>
20
+ module Helpers
21
+ def connection
22
+ raise StandardError, "mock model instances are not allowed to access the database"
23
+ end
24
+
25
+ def new_record?
26
+ id.nil?
27
+ end
28
+ end
29
+
30
+ module ActiveRecordHook
31
+ # Create a new instance of the class, pass in creation params and then
32
+ # yield the ModelMocker instance so that methods can be called on it
33
+ def self.mock(params = {})
34
+ mock_model = ModelMocker.new(self, params)
35
+ yield(mock_model) if block_given?
36
+ mock_model.instance
37
+ end
38
+ end
39
+
40
+ # ModelMocker.new is called with the AR::Base subclass a mock object is for,
41
+ # with any creation params in stub_params. Methods on the ModelMocker instance
42
+ # determine how the mock AR::Base subclass object will behave
43
+ def initialize(klass, stub_params = {})
44
+ @klass = klass
45
+ @stub_params = stub_params
46
+ end
47
+
48
+ def instance # :nodoc:
49
+ return @instance unless @instance.nil?
50
+ id = @stub_params[:id]
51
+ @instance = @klass.new
52
+ attributes.each do |k, v|
53
+ @instance.send(:write_attribute, k, v)
54
+ end
55
+ @instance.stubs(:id).returns(id)
56
+ stub_instance_methods!
57
+ @instance.extend(ModelMocker::Helpers)
58
+ @instance
59
+ end
60
+
61
+ # The model instance will report that it's a new record
62
+ def as_new_record
63
+ instance.stubs(:new_record?).returns(true)
64
+ end
65
+
66
+ # Validity-related methods will always report that the instance is valid,
67
+ # and <tt>#save</tt> and <tt>#save!</tt> will return true (without actually saving anything)
68
+ def valid
69
+ instance.stubs(:valid?).returns(true)
70
+ instance.stubs(:save).returns(true)
71
+ instance.stubs(:save!).returns(true)
72
+ end
73
+
74
+ # Validity-related methods will always report that the instance is invalid,
75
+ # <tt>#save</tt> will return false, and <tt>#save!</tt> will raise <tt>ActiveRecord::RecordNotSaved</tt>
76
+ def invalid
77
+ instance.stubs(:valid?).returns(false)
78
+ instance.stubs(:save).returns(false)
79
+ instance.stubs(:save!).raises(ActiveRecord::RecordNotSaved)
80
+ end
81
+
82
+ # The model instance cannot be updated: <tt>#update_attributes</tt> will always return false
83
+ def cannot_be_updated
84
+ instance.stubs(:update_attributes).returns(false)
85
+ end
86
+
87
+ # The model instance will return true if <tt>#destroy</tt> is called
88
+ def can_be_destroyed
89
+ instance.stubs(:destroy).returns(true)
90
+ end
91
+
92
+ # The model instance will return false if <tt>#destroy</tt> is called
93
+ def cannot_be_destroyed
94
+ instance.stubs(:destroy).returns(false)
95
+ end
96
+
97
+ protected
98
+
99
+ def valid_columns # :nodoc:
100
+ @valid_columns ||= @klass.columns_hash.collect { |k,v| k }
101
+ end
102
+
103
+ def attributes # :nodoc:
104
+ Hash[*(@stub_params.select { |attr_name, value| valid_columns.include?(attr_name.to_s) }.flatten)].reject {|k, v| k.to_s == 'id'}
105
+ end
106
+
107
+ def method_stubs # :nodoc:
108
+ Hash[*(@stub_params.reject { |attr_name, value| valid_columns.include?(attr_name.to_s) }.collect { |k, v| [k.to_sym, v] }).flatten]
109
+ end
110
+
111
+ def stub_instance_methods! # :nodoc:
112
+ method_stubs.each do |meth, value|
113
+ instance.stubs(meth).returns(value)
114
+ end
115
+ end
116
+ end
117
+
118
+ if defined?(Rails::Railtie)
119
+ require 'model_mocker/railtie'
120
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails'
2
+ require 'model_mocker'
3
+
4
+ module UrlKeyedObject
5
+ class Railtie < Rails::Railtie
6
+ initializer 'model_mocker.active_record_hook', :after => :preload_frameworks do
7
+ ::ActiveRecord::Base.extend ModelMocker::ActiveRecordHook
8
+ end
9
+ end
10
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'model_mocker'
2
+
3
+ if defined?(ActiveRecord::Base)
4
+ ActiveRecord::Base.extend ModelMocker::ActiveRecordHook
5
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper.rb')
2
+
3
+ class FakeARClass
4
+ class << self
5
+ def columns_hash
6
+ {'id' => :id, 'thing' => :thing, 'wotsit' => :wotsit}
7
+ end
8
+ end
9
+ end
10
+
11
+ describe ModelMocker do
12
+ describe "working out which args are attributes and which are method stubs" do
13
+ before(:each) do
14
+ @mm = ModelMocker.new(FakeARClass, {:id => 1, :thing => 'value', :wotsit => 'value', :gubbins => 'value'})
15
+ end
16
+
17
+ it "should figure out that :gubbins is not an attribute" do
18
+ ModelMocker.publicize_methods do
19
+ @mm.attributes.should == {:thing => 'value', :wotsit => 'value'}
20
+ end
21
+ end
22
+
23
+ it "should figure that :gubbins should be a method stub" do
24
+ ModelMocker.publicize_methods do
25
+ @mm.method_stubs.should == {:gubbins => 'value'}
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "working out which args are attributes and which are method stubs when the keys are strings not symbols" do
31
+ before(:each) do
32
+ @mm = ModelMocker.new(FakeARClass, {'id' => 1, 'thing' => 'value', 'wotsit' => 'value', 'gubbins' => 'value'})
33
+ end
34
+
35
+ it "should figure out that 'gubbins' is not an attribute" do
36
+ ModelMocker.publicize_methods do
37
+ @mm.attributes.should == {'thing' => 'value', 'wotsit' => 'value'}
38
+ end
39
+ end
40
+
41
+ it "should figure that 'gubbins' should be a method stub, and called :gubbins" do
42
+ ModelMocker.publicize_methods do
43
+ @mm.method_stubs.should == { :gubbins => 'value' }
44
+ end
45
+ end
46
+ end
47
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,33 @@
1
+ lib_path = File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
3
+
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+
8
+ gem 'activerecord'
9
+ require 'active_record'
10
+ require 'model_mocker'
11
+
12
+
13
+ Spec::Runner.configure do |config|
14
+ config.mock_with :mocha
15
+ end
16
+
17
+ class Class
18
+ def publicize_methods
19
+ saved_private_instance_methods = self.private_instance_methods
20
+ saved_protected_instance_methods = self.protected_instance_methods
21
+ self.class_eval do
22
+ public *saved_private_instance_methods
23
+ public *saved_protected_instance_methods
24
+ end
25
+
26
+ yield
27
+
28
+ self.class_eval do
29
+ private *saved_private_instance_methods
30
+ protected *saved_protected_instance_methods
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: model_mocker
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 1
8
+ - 1
9
+ version: 1.1.1
10
+ platform: ruby
11
+ authors:
12
+ - Matt Patterson
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-02 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: activerecord
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 2
43
+ - 3
44
+ version: "2.3"
45
+ type: :runtime
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: mocha
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ - 9
57
+ - 8
58
+ version: 0.9.8
59
+ type: :runtime
60
+ version_requirements: *id003
61
+ description: Declarative partial mocking for ActiveRecord
62
+ email: matt@reprocessed.org
63
+ executables: []
64
+
65
+ extensions: []
66
+
67
+ extra_rdoc_files:
68
+ - MIT-LICENSE
69
+ - README.rdoc
70
+ files:
71
+ - README.rdoc
72
+ - MIT-LICENSE
73
+ - Rakefile
74
+ - lib/model_mocker/railtie.rb
75
+ - lib/model_mocker.rb
76
+ - rails/init.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/fidothe/model_mocker
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Declarative partial mocking for ActiveRecord
107
+ test_files:
108
+ - spec/spec.opts
109
+ - spec/model_mocker_spec.rb
110
+ - spec/spec_helper.rb