flexmock 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  = Changes for FlexMock
4
4
 
5
+ == Version 0.5.0
6
+
7
+ * Added any_instance stubbing to class objects.
8
+
5
9
  == Version 0.4.5
6
10
 
7
11
  * Fixed version typo in 0.4.4 (internall claimed to be 0.4.3.1)
data/README CHANGED
@@ -3,7 +3,7 @@
3
3
  FlexMock is a simple, but flexible, mock object library for Ruby unit
4
4
  testing.
5
5
 
6
- Version :: 0.4.5
6
+ Version :: 0.5.0
7
7
 
8
8
  = Links
9
9
 
@@ -283,6 +283,37 @@ everything is back to normal.
283
283
  The stub technique was inspired by the +Stuba+ library in the +Mocha+
284
284
  project.
285
285
 
286
+ === Stubbing Behavior in All Instances Created by a Class Object
287
+
288
+ Sometimes you want to stub all instances created by a class object.
289
+ For example, you might wish to work with Connection objects that have
290
+ their "send" method stubbed out. However, the code under test creates
291
+ connections dynamically, so you can't stub them before the test is
292
+ run.
293
+
294
+ One approach is to stub the "new" method on the class object. The
295
+ stubbed implementation of "new" would create a mock object to be
296
+ returned as the value of "new". But since your stubbed implementation
297
+ of "new" has no access to the original behavior of new, you can't
298
+ really create stubs.
299
+
300
+ The <tt>any_instance</tt> method allows you to easily add stub
301
+ expectations to objects created by new. Here's the Connection example
302
+ using <tt>any_instance</tt>:
303
+
304
+ def test_connections
305
+ flexstub(Connection).any_instance do |new_con|
306
+ new_con.should_receive(:send).and_return(0)
307
+ end
308
+ connection = Connection.new
309
+ connection.send # This calls the stubbed version of send.
310
+ end
311
+
312
+ Note that FlexMock adds the stub expectations after the original +new+
313
+ method has completed. If the original version of +new+ yields the
314
+ newly created instance to a block, that block will get an unstubbed
315
+ version of the object.
316
+
286
317
  === Class Interception
287
318
 
288
319
  <b>NOTE:</b> ::
@@ -450,7 +481,7 @@ following:
450
481
 
451
482
  ruby-mock :: http://www.b13media.com/dev/ruby/mock.html
452
483
  test-unit-mock :: http://www.deveiate.org/code/Test-Unit-Mock.shtml
453
-
484
+ mocha/stubba :: http://mocha.rubyforge.org/
454
485
  == License
455
486
 
456
487
  Copyright 2003, 2004, 2005, 2006 by Jim Weirich (jim@weirichhouse.org).
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ require 'rake/testtask'
9
9
  CLEAN.include('*.tmp')
10
10
  CLOBBER.include("html", 'pkg')
11
11
 
12
- PKG_VERSION = '0.4.5'
12
+ PKG_VERSION = '0.5.0'
13
13
 
14
14
  PKG_FILES = FileList[
15
15
  '[A-Z]*',
@@ -41,18 +41,19 @@ end
41
41
 
42
42
  # RDoc Target --------------------------------------------------------
43
43
 
44
- rd = Rake::RDocTask.new("rdoc") do |rdoc|
44
+ task :rdoc => ["README"]
45
+
46
+ $rd = Rake::RDocTask.new("rdoc") do |rdoc|
45
47
  rdoc.rdoc_dir = 'html'
46
48
  rdoc.template = 'doc/jamis.rb'
47
- # rdoc.template = 'html'
48
- # rdoc.template = 'kilmer'
49
- # rdoc.template = 'css2'
49
+ # rdoc.template = 'html'
50
+ # rdoc.template = 'kilmer'
51
+ # rdoc.template = 'css2'
50
52
  rdoc.title = "Flex Mock"
51
53
  rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
52
54
  rdoc.rdoc_files.include(RDOC_FILES)
53
55
  end
54
56
 
55
- task :rdoc => ["README"]
56
57
  file "README" => ["Rakefile"] do
57
58
  ruby %{-i.bak -pe 'sub!(/^Version *:: *(\\d+\\.)+\\d+ *$/, "Version :: #{PKG_VERSION}")' README} # "
58
59
  end
@@ -95,7 +96,7 @@ else
95
96
  #### Documentation and testing.
96
97
 
97
98
  s.has_rdoc = true
98
- s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
99
+ s.extra_rdoc_files = $rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
99
100
  s.rdoc_options <<
100
101
  '--title' << 'Flex Mock' <<
101
102
  '--main' << 'README' <<
@@ -0,0 +1,103 @@
1
+ = FlexMock 0.5.0 Released
2
+
3
+ FlexMock is a flexible mocking library for use in Ruby's Test::Unit
4
+ test framework. Version 0.5.0 adds the ability to automatically stub any
5
+ instance created by an existing class.
6
+
7
+ == New in 0.5.0
8
+
9
+ * flexstub(obj) will now accept a block argument in the same way that
10
+ flexmock() does.
11
+
12
+ * When stubbing Class objects, the any_instance method can be used to
13
+ automatically stub any instance object created by the class. For
14
+ example, if you wish that any Connection object created during a test
15
+ has a stubbed "send" method, you could do the following:
16
+
17
+ def test_connections
18
+ flexstub(Connection).any_instance do |new_con|
19
+ new_con.should_receive(:send).and_return(0)
20
+ end
21
+ connection = Connection.new
22
+ connection.send # This calls the stubbed version of send.
23
+ end
24
+
25
+ Only objects created during the test will be automatically stubbed.
26
+ Existing objects are unaffected.
27
+
28
+ == What is FlexMock?
29
+
30
+ FlexMock is a flexible Ruby mocking library that works with Ruby's
31
+ Test::Unit framework to create easy to use mocks.
32
+
33
+ === Features
34
+
35
+ * Easy integration with Test::Unit. Mocks created with the flexmock
36
+ method are automatically verified at the end of the test.
37
+
38
+ * A fluent interface that allows mock behavior to be specified very
39
+ easily.
40
+
41
+ * A "record mode" where an existing implementation can record its
42
+ interaction with a mock for later validation against a new
43
+ implementation.
44
+
45
+ * Easy mocking of individual methods in existing, non-mock objects.
46
+
47
+ === Example
48
+
49
+ Suppose you had a Dog object that wagged a tail when it was happy.
50
+ Something like this:
51
+
52
+ class Dog
53
+ def initialize(a_tail)
54
+ @tail = a_tail
55
+ end
56
+ def happy
57
+ @tail.wag
58
+ end
59
+ end
60
+
61
+ To test the +Dog+ class without a real +Tail+ object (perhaps because
62
+ real +Tail+ objects activate servos in some robotic equipment), you
63
+ can do something like this:
64
+
65
+ require 'test/unit'
66
+ require 'flexmock'
67
+
68
+ class TestDog < Test::Unit::TestCase
69
+ include FlexMock::TestCase
70
+
71
+ def test_dog_wags_tail_when_happy
72
+ tail = flexmock("tail")
73
+ tail.should_receive(:wag).once
74
+ dog = Dog.new(tail)
75
+ dog.happy
76
+ end
77
+ end
78
+
79
+ FlexMock will automatically verify that the mocked tail object
80
+ received the message +wag+ exactly one time. If it doesn't, the test
81
+ will not pass.
82
+
83
+ See the FlexMock documentation at
84
+ http://onestepback.org/software/flexmock for details on specifying
85
+ arguments and return values on mocked methods, as well as a simple
86
+ technique for mocking tail objects when the Dog class creates the tail
87
+ objects directly.
88
+
89
+ == Availability
90
+
91
+ You can make sure you have the latest version with a quick RubyGems command:
92
+
93
+ gem install flexmock (you may need root/admin privileges)
94
+
95
+ Otherwise, you can get it from the more traditional places:
96
+
97
+ Download:: http://rubyforge.org/project/showfiles.php?group_id=170
98
+
99
+ You will find documentation at:
100
+ http://onestepback.org/software/flexmock/
101
+
102
+ -- Jim Weirich
103
+
@@ -26,9 +26,9 @@ require 'test/unit'
26
26
  #
27
27
  # m = FlexMock.new("name")
28
28
  # m.should_receive(:upcase).with("stuff").
29
- # returns("STUFF")
29
+ # and_return("STUFF")
30
30
  # m.should_receive(:downcase).with(String).
31
- # returns { |s| s.downcase }.once
31
+ # and_return { |s| s.downcase }.once
32
32
  #
33
33
  # With Test::Unit Integration:
34
34
  #
@@ -52,7 +52,7 @@ class FlexMock
52
52
  class BadInterceptionError < RuntimeError; end
53
53
 
54
54
  attr_reader :mock_name, :mock_groups
55
- attr_accessor :mock_current_order
55
+ attr_accessor :mock_current_order, :mock_container
56
56
 
57
57
  # Create a FlexMock object with the given name. The name is used in
58
58
  # error messages.
@@ -61,6 +61,7 @@ class FlexMock
61
61
  @expectations = Hash.new
62
62
  @allocated_order = 0
63
63
  @mock_current_order = 0
64
+ @mock_container = nil
64
65
  @mock_groups = {}
65
66
  @ignore_missing = false
66
67
  @verified = false
@@ -843,6 +844,7 @@ class FlexMock
843
844
  def flexmock_remember(mocking_object)
844
845
  @flexmock_created_mocks ||= []
845
846
  @flexmock_created_mocks << mocking_object
847
+ mocking_object.mock_container = self
846
848
  mocking_object
847
849
  end
848
850
  end
@@ -977,6 +979,7 @@ class FlexMock
977
979
  class StubProxy
978
980
  attr_reader :mock
979
981
 
982
+ # Initialize a StubProxy object.
980
983
  def initialize(obj, mock)
981
984
  @obj = obj
982
985
  @mock = mock
@@ -995,6 +998,32 @@ class FlexMock
995
998
  @mock.should_receive(method_name)
996
999
  end
997
1000
 
1001
+ # any_instance is a short cut method for overriding the behavior of any
1002
+ # instance created via a stubbed class object.
1003
+ def any_instance(&block)
1004
+ fail ArgumentError, "any_instance requires a Class to stub" unless Class === @obj
1005
+ self.should_receive(:new).and_return { |*args|
1006
+ new_obj = invoke_original(:new, args)
1007
+ mock = mock_container.flexstub(new_obj)
1008
+ block.call(mock)
1009
+ new_obj
1010
+ }
1011
+ nil
1012
+ end
1013
+
1014
+ # Invoke the original definition of method on the object supported by
1015
+ # the stub.
1016
+ def invoke_original(method, args)
1017
+ method_proc = @method_definitions[:new]
1018
+ block = nil
1019
+ if Proc === args.last
1020
+ block = args.last
1021
+ args = args[0...-1]
1022
+ end
1023
+ method_proc.call(*args, &block)
1024
+ end
1025
+ private :invoke_original
1026
+
998
1027
  # Verify that the mock has been properly called. After verification,
999
1028
  # detach the mocking infrastructure from the existing object.
1000
1029
  def mock_verify
@@ -1012,6 +1041,18 @@ class FlexMock
1012
1041
  @obj = nil
1013
1042
  end
1014
1043
  end
1044
+
1045
+ # Return the container for this mocking object. Returns nil if the
1046
+ # mock is not in a container. Mock containers make sure that mock objects
1047
+ # inside the container are torn down at the end of a test
1048
+ def mock_container
1049
+ @mock.mock_container
1050
+ end
1051
+
1052
+ # Set the container for this mock object.
1053
+ def mock_container=(container)
1054
+ @mock.mock_container = container
1055
+ end
1015
1056
 
1016
1057
  private
1017
1058
 
@@ -1033,10 +1074,8 @@ class FlexMock
1033
1074
  # not a singleton, all we need to do is override it with our own
1034
1075
  # singleton.
1035
1076
  def hide_existing_method(method_name)
1036
- if singleton?(method_name)
1037
- @method_definitions[method_name] = @obj.method(method_name)
1038
- remove_current_method(method_name)
1039
- end
1077
+ @method_definitions[method_name] = @obj.method(method_name) if @obj.respond_to?(method_name)
1078
+ remove_current_method(method_name) if singleton?(method_name)
1040
1079
  define_proxy_method(method_name)
1041
1080
  end
1042
1081
 
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #---
4
+ # Copyright 2006 by Jim Weirich (jweirich@one.net).
5
+ # All rights reserved.
6
+
7
+ # Permission is granted for use, copying, modification, distribution,
8
+ # and distribution of modified versions of this work as long as the
9
+ # above copyright notice is included.
10
+ #+++
11
+
12
+ require 'test/unit'
13
+ require 'flexmock'
14
+
15
+ class TestStubbingOnNew < Test::Unit::TestCase
16
+ include FlexMock::TestCase
17
+
18
+ class Dog
19
+ def bark
20
+ :woof
21
+ end
22
+ def wag
23
+ :tail
24
+ end
25
+ end
26
+
27
+ class Cat
28
+ attr_reader :name
29
+ def initialize(name, &block)
30
+ @name = name
31
+ block.call(self) if block_given?
32
+ end
33
+ end
34
+
35
+ class Connection
36
+ def initialize(*args)
37
+ yield(self) if block_given?
38
+ end
39
+ def send(args)
40
+ post(args)
41
+ end
42
+ def post(args)
43
+ :unstubbed
44
+ end
45
+ end
46
+
47
+ def test_any_instance_allows_stubbing_of_existing_methods
48
+ flexstub(Dog).any_instance do |obj|
49
+ obj.should_receive(:bark).and_return(:whimper)
50
+ end
51
+ m = Dog.new
52
+ assert_equal :whimper, m.bark
53
+ end
54
+
55
+ def test_any_instance_stubs_still_have_existing_methods
56
+ flexstub(Dog).any_instance do |obj|
57
+ obj.should_receive(:bark).and_return(:whimper)
58
+ end
59
+ m = Dog.new
60
+ assert_equal :tail, m.wag
61
+ end
62
+
63
+ def test_any_instance_will_pass_args_to_new
64
+ flexstub(Cat).any_instance do |obj|
65
+ obj.should_receive(:meow).and_return(:scratch)
66
+ end
67
+ x = :not_called
68
+ m = Cat.new("Fido") { x = :called }
69
+ assert_equal :scratch, m.meow
70
+ assert_equal "Fido", m.name
71
+ assert_equal :called, x
72
+ end
73
+
74
+ def test_any_instance_stub_verification_happens_on_teardown
75
+ flexstub(Dog).any_instance do |obj|
76
+ obj.should_receive(:bark).once.and_return(nil)
77
+ end
78
+
79
+ fido = Dog.new
80
+ ex = assert_raise(Test::Unit::AssertionFailedError) { flexmock_teardown }
81
+ assert_match(/method 'bark\(.*\)' called incorrect number of times/, ex.message)
82
+ end
83
+
84
+ def test_any_instance_reports_error_on_non_classes
85
+ ex = assert_raise(ArgumentError) {
86
+ flexstub(Dog.new).any_instance do |obj|
87
+ obj.should_receive(:hi)
88
+ end
89
+ }
90
+ assert_match(/Class/, ex.message)
91
+ assert_match(/any_instance/, ex.message)
92
+ end
93
+
94
+ # Current behavior does not install stubs into the block passed to new.
95
+ # This is rather difficult to achieve, although it would be nice. For the
96
+ # moment, we assure that they are not stubbed, but I am willing to change
97
+ # this in the future.
98
+ def test_blocks_on_new_do_not_have_stubs_installed
99
+ flexstub(Connection).any_instance do |new_con|
100
+ new_con.should_receive(:post).and_return {
101
+ :stubbed
102
+ }
103
+ end
104
+ block_run = false
105
+ Connection.new do |c|
106
+ assert_equal :unstubbed, c.send("hi")
107
+ block_run = true
108
+ end
109
+ assert block_run
110
+ end
111
+ end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0.10
2
+ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: flexmock
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.5
7
- date: 2007-01-26 00:00:00 -05:00
6
+ version: 0.5.0
7
+ date: 2007-02-10 00:00:00 -05:00
8
8
  summary: Simple and Flexible Mock Objects for Testing
9
9
  require_paths:
10
10
  - lib
@@ -33,6 +33,7 @@ files:
33
33
  - Rakefile
34
34
  - README
35
35
  - lib/flexmock.rb
36
+ - test/test_any_instance.rb
36
37
  - test/test_class_interception.rb
37
38
  - test/test_example.rb
38
39
  - test/test_mock.rb
@@ -48,6 +49,7 @@ files:
48
49
  - doc/releases/flexmock-0.4.1.rdoc
49
50
  - doc/releases/flexmock-0.4.2.rdoc
50
51
  - doc/releases/flexmock-0.4.3.rdoc
52
+ - doc/releases/flexmock-0.5.0.rdoc
51
53
  test_files: []
52
54
 
53
55
  rdoc_options:
@@ -63,6 +65,7 @@ extra_rdoc_files:
63
65
  - doc/releases/flexmock-0.4.1.rdoc
64
66
  - doc/releases/flexmock-0.4.2.rdoc
65
67
  - doc/releases/flexmock-0.4.3.rdoc
68
+ - doc/releases/flexmock-0.5.0.rdoc
66
69
  executables: []
67
70
 
68
71
  extensions: []