flexmock 0.9.0 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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