flexmock 0.9.0 → 1.0.0.beta.1

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.
Files changed (53) hide show
  1. data/README.rdoc +325 -177
  2. data/Rakefile +22 -8
  3. data/TAGS +772 -669
  4. data/doc/releases/flexmock-1.0.0.rdoc +128 -0
  5. data/lib/flexmock.rb +1 -1
  6. data/lib/flexmock/argument_matchers.rb +16 -3
  7. data/lib/flexmock/argument_matching.rb +33 -0
  8. data/lib/flexmock/argument_types.rb +5 -1
  9. data/lib/flexmock/base.rb +1 -1
  10. data/lib/flexmock/composite.rb +3 -3
  11. data/lib/flexmock/core.rb +32 -2
  12. data/lib/flexmock/core_class_methods.rb +1 -1
  13. data/lib/flexmock/default_framework_adapter.rb +1 -1
  14. data/lib/flexmock/deprecated_methods.rb +1 -1
  15. data/lib/flexmock/errors.rb +1 -1
  16. data/lib/flexmock/expectation.rb +15 -13
  17. data/lib/flexmock/expectation_director.rb +1 -1
  18. data/lib/flexmock/explicit_needed.rb +39 -0
  19. data/lib/flexmock/mock_container.rb +8 -2
  20. data/lib/flexmock/noop.rb +1 -1
  21. data/lib/flexmock/ordering.rb +1 -1
  22. data/lib/flexmock/partial_mock.rb +12 -2
  23. data/lib/flexmock/rails.rb +1 -1
  24. data/lib/flexmock/recorder.rb +1 -1
  25. data/lib/flexmock/rspec.rb +5 -1
  26. data/lib/flexmock/rspec_spy_matcher.rb +74 -0
  27. data/lib/flexmock/spy_describers.rb +60 -0
  28. data/lib/flexmock/test_unit.rb +1 -1
  29. data/lib/flexmock/test_unit_assert_spy_called.rb +34 -0
  30. data/lib/flexmock/test_unit_integration.rb +3 -1
  31. data/lib/flexmock/undefined.rb +1 -1
  32. data/lib/flexmock/validators.rb +1 -1
  33. data/lib/flexmock/version.rb +4 -2
  34. data/test/assert_spy_called_test.rb +89 -0
  35. data/test/container_methods_test.rb +1 -1
  36. data/test/default_framework_adapter_test.rb +1 -1
  37. data/test/deprecated_methods_test.rb +1 -1
  38. data/test/examples_from_readme_test.rb +1 -1
  39. data/test/extended_should_receive_test.rb +1 -1
  40. data/test/naming_test.rb +1 -2
  41. data/test/new_instances_test.rb +1 -3
  42. data/test/partial_mock_test.rb +7 -1
  43. data/test/record_mode_test.rb +1 -1
  44. data/test/rspec_integration/integration_spec.rb +11 -3
  45. data/test/rspec_integration/spy_example_spec.rb +141 -0
  46. data/test/samples_test.rb +1 -1
  47. data/test/should_ignore_missing_test.rb +6 -2
  48. data/test/should_receive_test.rb +31 -2
  49. data/test/spys_test.rb +148 -0
  50. data/test/test_unit_integration/auto_test_unit_test.rb +1 -1
  51. data/test/tu_integration_test.rb +1 -1
  52. data/test/undefined_test.rb +1 -1
  53. metadata +16 -8
@@ -0,0 +1,128 @@
1
+ = FlexMock 1.0.0 Released
2
+
3
+ FlexMock is a flexible mocking library for use in unit testing and
4
+ behavior specification in Ruby. Release 1.0.0 is a minor release with
5
+ a few bug fixes.
6
+
7
+ == Changes in 1.0.0
8
+
9
+ * Mocks may now have a base class that limits what methods may be
10
+ mocked. This allows early detection of outdated mock setups when the
11
+ methods in the class are refactored.
12
+
13
+ * Spy assertions are now allowed. The verification of the calling of
14
+ mocked methods may now be done in the "then" portion of the test,
15
+ after the code under test has been run. This allows for much more
16
+ natural Given/When/Then style testing.
17
+
18
+ * A custom assert method (assert_spy_called) has been added to make
19
+ spy assertions easy when using Test::Unit or MiniTest.
20
+
21
+ * An RSpec matcher (have_received) has been added to make spy
22
+ assertions easy when using RSpec.
23
+
24
+ == What is FlexMock?
25
+
26
+ FlexMock is a flexible framework for creating mock object for testing. When
27
+ running unit tests, it is often desirable to use isolate the objects being
28
+ tested from the "real world" by having them interact with simplified test
29
+ objects. Sometimes these test objects simply return values when called, other
30
+ times they verify that certain methods were called with particular arguments
31
+ in a particular order.
32
+
33
+ FlexMock makes creating these test objects easy.
34
+
35
+ === Features
36
+
37
+ * Easy integration with both Test::Unit and RSpec. Mocks created with the
38
+ flexmock method are automatically verified at the end of the test or
39
+ example.
40
+
41
+ * A fluent interface that allows mock behavior to be specified very
42
+ easily.
43
+
44
+ * A "record mode" where an existing implementation can record its
45
+ interaction with a mock for later validation against a new
46
+ implementation.
47
+
48
+ * Easy mocking of individual methods in existing, non-mock objects.
49
+
50
+ * Easy mocking of chains of method calls.
51
+
52
+ * The ability to cause classes to instantiate test instances (instead of real
53
+ instances) for the duration of a test.
54
+
55
+ === Example
56
+
57
+ Suppose you had a Dog object that wagged a tail when it was happy.
58
+ Something like this:
59
+
60
+ class Dog
61
+ def initialize(a_tail)
62
+ @tail = a_tail
63
+ end
64
+ def happy
65
+ @tail.wag
66
+ end
67
+ end
68
+
69
+ To test the +Dog+ class without a real +Tail+ object (perhaps because
70
+ real +Tail+ objects activate servos in some robotic equipment), you
71
+ can do something like this:
72
+
73
+ RSpec.configure do |config|
74
+ config.mock_with :flexmock
75
+ end
76
+
77
+ describe Dog do
78
+ it "wags its tail when happy" do
79
+ tail = flexmock("tail")
80
+ tail.should_receive(:wag).once
81
+ dog = Dog.new(tail)
82
+ dog.happy
83
+ end
84
+ end
85
+
86
+ FlexMock will automatically verify that the mocked tail object received the
87
+ message +wag+ exactly one time. If it doesn't, the test will not pass.
88
+
89
+ Here's the same thing using the new spy support:
90
+
91
+ describe Dog do
92
+ it "wags its tail when happy" do
93
+ tail = flexmock("tail")
94
+ dog = Dog.new(tail)
95
+ dog.happy
96
+ tail.should have_received(:wag)
97
+ end
98
+ end
99
+
100
+ This style works particularly well with the rspec-given library.
101
+
102
+ require 'rspec/given'
103
+
104
+ describe Dog do
105
+ context "when the dog is happy" do
106
+ Given(:tail) { flexmock(:on, Tail) }
107
+ Given(:dog) { Dog.new(tail) }
108
+
109
+ When { dog.happy }
110
+
111
+ Then { tail.should have_received(:wag) }
112
+ end
113
+ end
114
+
115
+ See the FlexMock documentation at http://flexmock.rubyforge.org for details on
116
+ specifying arguments and return values on mocked methods, as well as a simple
117
+ technique for mocking tail objects when the Dog class creates the tail objects
118
+ directly.
119
+
120
+ == Availability
121
+
122
+ You can make sure you have the latest version with a quick RubyGems command:
123
+
124
+ gem install flexmock (you may need root/admin privileges)
125
+
126
+ You will find documentation at: http://flexmock.rubyforge.org.
127
+
128
+ -- Jim Weirich
data/lib/flexmock.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
 
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
  #
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -54,7 +54,7 @@ class FlexMock
54
54
  end
55
55
 
56
56
  ####################################################################
57
- # Match only things where the block evaluates to true.
57
+ # Match hashes that match all the fields of +hash+.
58
58
  class HashMatcher
59
59
  def initialize(hash)
60
60
  @hash = hash
@@ -68,7 +68,7 @@ class FlexMock
68
68
  end
69
69
 
70
70
  ####################################################################
71
- # Match only things where the block evaluates to true.
71
+ # Match objects that implement all the methods in +methods+.
72
72
  class DuckMatcher
73
73
  def initialize(methods)
74
74
  @methods = methods
@@ -81,5 +81,18 @@ class FlexMock
81
81
  end
82
82
  end
83
83
 
84
+ ####################################################################
85
+ # Match objects that implement all the methods in +methods+.
86
+ class OptionalProcMatcher
87
+ def initialize
88
+ end
89
+ def ===(target)
90
+ ArgumentMatching.missing?(target) || Proc === target
91
+ end
92
+ def inspect
93
+ "optional_proc"
94
+ end
95
+ end
96
+ OPTIONAL_PROC_MATCHER = OptionalProcMatcher.new
84
97
 
85
98
  end
@@ -0,0 +1,33 @@
1
+ class FlexMock
2
+ module ArgumentMatching
3
+ module_function
4
+
5
+ MISSING_ARG = Object.new
6
+
7
+ def all_match?(expected_args, actual_args)
8
+ return true if expected_args.nil?
9
+ return false if actual_args.size > expected_args.size
10
+ i = 0
11
+ while i < actual_args.size
12
+ return false unless match?(expected_args[i], actual_args[i])
13
+ i += 1
14
+ end
15
+ while i < expected_args.size
16
+ return false unless match?(expected_args[i], MISSING_ARG)
17
+ i += 1
18
+ end
19
+ true
20
+ end
21
+
22
+ # Does the expected argument match the corresponding actual value.
23
+ def match?(expected, actual)
24
+ expected === actual ||
25
+ expected == actual ||
26
+ ( Regexp === expected && expected === actual.to_s )
27
+ end
28
+
29
+ def missing?(arg)
30
+ arg == MISSING_ARG
31
+ end
32
+ end
33
+ end
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
 
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -48,6 +48,10 @@ class FlexMock
48
48
  def ducktype(*methods)
49
49
  DuckMatcher.new(methods)
50
50
  end
51
+
52
+ def optional_proc
53
+ OPTIONAL_PROC_MATCHER
54
+ end
51
55
  end
52
56
  extend ArgumentTypes
53
57
 
data/lib/flexmock/base.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
 
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # Created by Jim Weirich on 2007-04-14.
4
- # Copyright (c) 2007. All rights reserved.
3
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
4
+ # All rights reserved.
5
5
 
6
6
  require 'flexmock/noop'
7
7
 
8
8
  class FlexMock
9
9
 
10
- end
10
+ end
data/lib/flexmock/core.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
  #
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -12,6 +12,8 @@
12
12
  require 'flexmock/errors'
13
13
  require 'flexmock/composite'
14
14
  require 'flexmock/ordering'
15
+ require 'flexmock/argument_matching'
16
+ require 'flexmock/explicit_needed'
15
17
 
16
18
  ######################################################################
17
19
  # FlexMock is a flexible mock object framework for supporting testing.
@@ -57,6 +59,8 @@ class FlexMock
57
59
  @expectations = Hash.new
58
60
  @ignore_missing = false
59
61
  @verified = false
62
+ @calls = []
63
+ @base_class = nil
60
64
  container = UseContainer.new if container.nil?
61
65
  container.flexmock_remember(self)
62
66
  end
@@ -85,6 +89,7 @@ class FlexMock
85
89
  # Ignore all undefined (missing) method calls.
86
90
  def should_ignore_missing
87
91
  @ignore_missing = true
92
+ self
88
93
  end
89
94
  alias mock_ignore_missing should_ignore_missing
90
95
 
@@ -95,10 +100,13 @@ class FlexMock
95
100
 
96
101
  # Handle missing methods by attempting to look up a handler.
97
102
  def method_missing(sym, *args, &block)
103
+ @calls << [sym, block_given? ? args + [block] : args]
98
104
  flexmock_wrap do
99
105
  if handler = @expectations[sym]
100
106
  args << block if block_given?
101
107
  handler.call(*args)
108
+ elsif @base_class && @base_class.instance_methods.include?(sym)
109
+ FlexMock.undefined
102
110
  elsif @ignore_missing
103
111
  FlexMock.undefined
104
112
  else
@@ -126,6 +134,27 @@ class FlexMock
126
134
  @expectations[method_name]
127
135
  end
128
136
 
137
+ def flexmock_spies_on(base_class)
138
+ @base_class = base_class
139
+ end
140
+
141
+ def flexmock_was_called_with?(sym, args, options={})
142
+ count = 0
143
+ @calls.each { |call_sym, call_args, call_block|
144
+ count += 1 if (call_sym == sym) && ArgumentMatching.all_match?(args, call_args)
145
+ }
146
+ if options[:times]
147
+ result = count == options[:times]
148
+ else
149
+ result = count > 0
150
+ end
151
+ result
152
+ end
153
+
154
+ def flexmock_invoke_original(sym, args)
155
+ return FlexMock.undefined
156
+ end
157
+
129
158
  # Override the built-in +method+ to include the mocked methods.
130
159
  def method(sym)
131
160
  @expectations[sym] || super
@@ -162,9 +191,10 @@ class FlexMock
162
191
  result = Expectation.new(self, sym)
163
192
  @expectations[sym] << result
164
193
  override_existing_method(sym) if flexmock_respond_to?(sym)
194
+ result = ExplicitNeeded.new(result, sym, @base_class) if
195
+ @base_class && ! @base_class.instance_methods.include?(sym)
165
196
  result
166
197
  end
167
- @last_expectation
168
198
  end
169
199
 
170
200
  # Declare that the mock object should expect methods by providing a
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
 
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
 
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
  #
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
  #
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  #---
4
- # Copyright 2003-2011 by Jim Weirich (jim@weirichhouse.org).
4
+ # Copyright 2003-2012 by Jim Weirich (jim.weirich@gmail.com).
5
5
  # All rights reserved.
6
6
 
7
7
  # Permission is granted for use, copying, modification, distribution,
@@ -10,6 +10,7 @@
10
10
  #+++
11
11
 
12
12
  require 'flexmock/noop'
13
+ require 'flexmock/argument_matching'
13
14
 
14
15
  class FlexMock
15
16
 
@@ -127,18 +128,7 @@ class FlexMock
127
128
  # Does the argument list match this expectation's argument
128
129
  # specification.
129
130
  def match_args(args)
130
- # TODO: Rethink this:
131
- # return false if @expected_args.nil?
132
- return true if @expected_args.nil?
133
- return false if args.size != @expected_args.size
134
- (0...args.size).all? { |i| match_arg(@expected_args[i], args[i]) }
135
- end
136
-
137
- # Does the expected argument match the corresponding actual value.
138
- def match_arg(expected, actual)
139
- expected === actual ||
140
- expected == actual ||
141
- ( Regexp === expected && expected === actual.to_s )
131
+ ArgumentMatching.all_match?(@expected_args, args)
142
132
  end
143
133
 
144
134
  # Declare that the method should expect the given argument list.
@@ -268,6 +258,12 @@ class FlexMock
268
258
  end
269
259
  alias :throws :and_throw
270
260
 
261
+ def pass_thru
262
+ and_return { |*args|
263
+ @mock.flexmock_invoke_original(@sym, args)
264
+ }
265
+ end
266
+
271
267
  # Declare that the method may be called any number of times.
272
268
  def zero_or_more_times
273
269
  at_least.never
@@ -385,6 +381,12 @@ class FlexMock
385
381
  end
386
382
  private :define_ordered
387
383
 
384
+ # No-op for allowing explicit calls when explicit not explicitly
385
+ # needed.
386
+ def explicit
387
+ self
388
+ end
389
+
388
390
  def by_default
389
391
  expectations = mock.flexmock_expectations_for(@sym)
390
392
  expectations.defaultify_expectation(self) if expectations