flexmock 1.3.0 → 1.3.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.
@@ -4,7 +4,7 @@ FlexMock is a simple, but flexible, mock object library for Ruby unit
4
4
  testing.
5
5
 
6
6
  This is the API documentation site for flexmock. You can find the user
7
- documentation at http://github.com/jimweirich/flexmock.
7
+ documentation at http://github.com/jimweirich/flexmock
8
8
 
9
9
  == Links
10
10
 
@@ -0,0 +1,171 @@
1
+ = FlexMock 1.3.1 Released
2
+
3
+ FlexMock is a flexible mocking library for use in unit testing and
4
+ behavior specification in Ruby. This release is a minor release with a
5
+ few bug fixes and some simple features.
6
+
7
+ == Changes in 1.3.1
8
+
9
+ * Removed use of assert_block (which is deprecated in MiniTest).
10
+
11
+ * Documentation fixes.
12
+
13
+ == Changes in 1.3.0
14
+
15
+ === Features
16
+
17
+ * Add 'and' and 'on' modifiers for the RSpec spy matcher.
18
+
19
+ * Add 'and' and 'on' options to the assert_spy_called test method.
20
+
21
+ * General documentation improvement.
22
+
23
+ === Bug Fixes
24
+
25
+ * Fix bug in should_fail test helper that was not detecting failed
26
+ failures.
27
+
28
+ == Changes in 1.2.0
29
+
30
+ === Features
31
+
32
+ * Add auto configure by requiring 'flexmock/rspec/configure'.
33
+
34
+ == Changes in 1.1.0
35
+
36
+ === Features
37
+
38
+ * Add block support to pass_thru.
39
+
40
+ == Changes in 1.0.0
41
+
42
+ === Features
43
+
44
+ * Mocks may now have a base class that limits what methods may be
45
+ mocked. This allows early detection of outdated mock setups when the
46
+ methods in the class are refactored.
47
+
48
+ * Spy assertions are now allowed. The verification of the calling of
49
+ mocked methods may now be done in the "then" portion of the test,
50
+ after the code under test has been run. This allows for much more
51
+ natural Given/When/Then style testing.
52
+
53
+ * A custom assert method (assert_spy_called) has been added to make
54
+ spy assertions easy when using Test::Unit or MiniTest.
55
+
56
+ * An RSpec matcher (have_received) has been added to make spy
57
+ assertions easy when using RSpec.
58
+
59
+ === Bug Fixes
60
+
61
+ * Now correctly handling the mocking of meta-programmed methods.
62
+
63
+ * Using the documented +singleton_methods+ method.
64
+
65
+ * Accidently trying to partial mock a regular mock is now a no-op.
66
+
67
+ == What is FlexMock?
68
+
69
+ FlexMock is a flexible framework for creating mock object for testing.
70
+ When running unit tests, it is often desirable to use isolate the
71
+ objects being tested from the "real world" by having them interact
72
+ with simplified test objects. Sometimes these test objects simply
73
+ return values when called, other times they verify that certain
74
+ methods were called with particular arguments in a particular order.
75
+
76
+ FlexMock makes creating these test objects easy.
77
+
78
+ === Features
79
+
80
+ * Easy integration with both Test::Unit and RSpec. Mocks created with the
81
+ flexmock method are automatically verified at the end of the test or
82
+ example.
83
+
84
+ * A fluent interface that allows mock behavior to be specified very
85
+ easily.
86
+
87
+ * A "record mode" where an existing implementation can record its
88
+ interaction with a mock for later validation against a new
89
+ implementation.
90
+
91
+ * Easy mocking of individual methods in existing, non-mock objects.
92
+
93
+ * Easy mocking of chains of method calls.
94
+
95
+ * The ability to cause classes to instantiate test instances (instead of real
96
+ instances) for the duration of a test.
97
+
98
+ === Example
99
+
100
+ Suppose you had a Dog object that wagged a tail when it was happy.
101
+ Something like this:
102
+
103
+ class Dog
104
+ def initialize(a_tail)
105
+ @tail = a_tail
106
+ end
107
+ def happy
108
+ @tail.wag
109
+ end
110
+ end
111
+
112
+ To test the +Dog+ class without a real +Tail+ object (perhaps because
113
+ real +Tail+ objects activate servos in some robotic equipment), you
114
+ can do something like this:
115
+
116
+ RSpec.configure do |config|
117
+ config.mock_with :flexmock
118
+ end
119
+
120
+ describe Dog do
121
+ it "wags its tail when happy" do
122
+ tail = flexmock("tail")
123
+ tail.should_receive(:wag).once
124
+ dog = Dog.new(tail)
125
+ dog.happy
126
+ end
127
+ end
128
+
129
+ FlexMock will automatically verify that the mocked tail object received the
130
+ message +wag+ exactly one time. If it doesn't, the test will not pass.
131
+
132
+ Here's the same thing using the new spy support:
133
+
134
+ describe Dog do
135
+ it "wags its tail when happy" do
136
+ tail = flexmock("tail")
137
+ dog = Dog.new(tail)
138
+ dog.happy
139
+ tail.should have_received(:wag)
140
+ end
141
+ end
142
+
143
+ This style works particularly well with the rspec-given library.
144
+
145
+ require 'rspec/given'
146
+
147
+ describe Dog do
148
+ context "when the dog is happy" do
149
+ Given(:tail) { flexmock(:on, Tail) }
150
+ Given(:dog) { Dog.new(tail) }
151
+
152
+ When { dog.happy }
153
+
154
+ Then { tail.should have_received(:wag) }
155
+ end
156
+ end
157
+
158
+ See the FlexMock documentation at http://flexmock.rubyforge.org for details on
159
+ specifying arguments and return values on mocked methods, as well as a simple
160
+ technique for mocking tail objects when the Dog class creates the tail objects
161
+ directly.
162
+
163
+ == Availability
164
+
165
+ You can make sure you have the latest version with a quick RubyGems command:
166
+
167
+ gem install flexmock (you may need root/admin privileges)
168
+
169
+ You will find documentation at: http://flexmock.rubyforge.org.
170
+
171
+ -- Jim Weirich
@@ -52,6 +52,11 @@ class FlexMock
52
52
  attr_reader :flexmock_name
53
53
  attr_accessor :flexmock_container
54
54
 
55
+ class << self
56
+ attr_accessor :partials_are_based
57
+ end
58
+ self.partials_are_based = false
59
+
55
60
  # Create a FlexMock object with the given name. The name is used in
56
61
  # error messages. If no container is given, create a new, one-off
57
62
  # container for this mock.
@@ -67,7 +67,7 @@ class FlexMock
67
67
  # Check will assert the block returns true. If it doesn't, an
68
68
  # assertion failure is triggered with the given message.
69
69
  def check(msg, &block) # :nodoc:
70
- FlexMock.framework_adapter.assert_block(msg, &block)
70
+ FlexMock.framework_adapter.make_assertion(msg, &block)
71
71
  end
72
72
 
73
73
  end
@@ -13,7 +13,7 @@ require 'flexmock/noop'
13
13
 
14
14
  class FlexMock
15
15
  class DefaultFrameworkAdapter
16
- def assert_block(msg, &block)
16
+ def make_assertion(msg, &block)
17
17
  unless yield
18
18
  msg = msg.call if msg.is_a?(Proc)
19
19
  fail assertion_failed_error, msg
@@ -21,7 +21,7 @@ class FlexMock
21
21
  end
22
22
 
23
23
  def assert_equal(a, b, msg=nil)
24
- assert_block(msg || "Expected equal") { a == b }
24
+ make_assertion(msg || "Expected equal") { a == b }
25
25
  end
26
26
 
27
27
  class AssertionFailedError < StandardError; end
@@ -5,7 +5,7 @@ class FlexMock
5
5
  # methods supported by the base class. Attempting to add an stub to
6
6
  # a method not defined on the base class will cause the expectation
7
7
  # to be wrapped in an ExplicitNeeded wrapper. The wrapper will throw
8
- # an exception unless the explicit method is immediately called on
8
+ # an exception unless the explicitly method is immediately called on
9
9
  # the expectation.
10
10
  #
11
11
  class ExplicitNeeded
@@ -25,6 +25,10 @@ class FlexMock
25
25
  @explicit
26
26
  end
27
27
 
28
+ def mock=(m)
29
+ @expectation.mock = m
30
+ end
31
+
28
32
  def method_missing(sym, *args, &block)
29
33
  if explicit?
30
34
  @expectation.send(sym, *args, &block)
@@ -160,7 +160,11 @@ class FlexMock
160
160
  mock ||= FlexMock.new(name || "unknown", self)
161
161
  result = mock
162
162
  end
163
- mock.flexmock_based_on(base_class) if base_class
163
+ if base_class
164
+ mock.flexmock_based_on(base_class)
165
+ elsif domain_obj && FlexMock.partials_are_based
166
+ mock.flexmock_based_on(domain_obj.class)
167
+ end
164
168
  mock.flexmock_define_expectation(location, quick_defs)
165
169
  yield(mock) if block_given?
166
170
  flexmock_remember(mock)
@@ -205,6 +205,11 @@ class FlexMock
205
205
  @mock.flexmock_expectations_for(method_name)
206
206
  end
207
207
 
208
+ # Forward the based on request.
209
+ def flexmock_based_on(*args)
210
+ @mock.flexmock_based_on(*args)
211
+ end
212
+
208
213
  private
209
214
 
210
215
  def check_allocate_method(allocate_method)
@@ -21,14 +21,14 @@ class FlexMock
21
21
  end
22
22
 
23
23
  class RSpecFrameworkAdapter
24
- def assert_block(msg, &block)
24
+ def make_assertion(msg, &block)
25
25
  msg = msg.call if msg.is_a?(Proc)
26
26
  SpecModule::Expectations.fail_with(msg) unless yield
27
27
  end
28
28
 
29
29
  def assert_equal(a, b, msg=nil)
30
30
  message = msg || "Expected equal"
31
- assert_block(message + "\n<#{a}> expected, but was\n<#{b}>") { a == b }
31
+ make_assertion(message + "\n<#{a}> expected, but was\n<#{b}>") { a == b }
32
32
  end
33
33
 
34
34
  class AssertionFailedError < StandardError; end
@@ -9,7 +9,7 @@
9
9
  # above copyright notice is included.
10
10
  #+++
11
11
 
12
- require 'test/unit'
12
+ require 'test/unit/assertions'
13
13
  require 'flexmock/base'
14
14
  require 'flexmock/test_unit_assert_spy_called'
15
15
 
@@ -47,10 +47,10 @@ class FlexMock
47
47
  class TestUnitFrameworkAdapter
48
48
  include Test::Unit::Assertions
49
49
 
50
- def assert_block(msg, &block)
50
+ def make_assertion(msg, &block)
51
51
  unless yield
52
52
  msg = msg.call if msg.is_a?(Proc)
53
- super(msg) { false }
53
+ assert(false, msg)
54
54
  end
55
55
  rescue assertion_failed_error => ex
56
56
  ex.message.sub!(/Expected block to return true value./,'')
@@ -50,6 +50,22 @@ class FlexMock
50
50
  ".times(#{@limit})"
51
51
  end
52
52
  end
53
+
54
+ def describe_limit
55
+ @limit.to_s
56
+ end
57
+
58
+ def validate_count(n, &block)
59
+ @exp.flexmock_location_filter do
60
+ FlexMock.framework_adapter.make_assertion(
61
+ lambda {
62
+ "Method '#{@exp}' called incorrect number of times\n" +
63
+ "#{describe_limit} matching #{calls(@limit)} expected\n" +
64
+ "#{n} matching #{calls(n)} found\n" +
65
+ describe_calls(@exp.mock)
66
+ }, &block)
67
+ end
68
+ end
53
69
  end
54
70
 
55
71
  ####################################################################
@@ -59,16 +75,7 @@ class FlexMock
59
75
  # Validate that the method expectation was called exactly +n+
60
76
  # times.
61
77
  def validate(n)
62
- @exp.flexmock_location_filter do
63
- FlexMock.framework_adapter.assert_block(
64
- lambda {
65
- "Method '#{@exp}' called incorrect number of times\n" +
66
- "#{@limit} matching #{calls(@limit)} expected\n" +
67
- "#{n} matching #{calls(n)} found\n" +
68
- describe_calls(@exp.mock)
69
- }
70
- ) { @limit == n }
71
- end
78
+ validate_count(n) { @limit == n }
72
79
  end
73
80
  end
74
81
 
@@ -79,15 +86,7 @@ class FlexMock
79
86
  # Validate the method expectation was called no more than +n+
80
87
  # times.
81
88
  def validate(n)
82
- @exp.flexmock_location_filter do
83
- FlexMock.framework_adapter.assert_block(
84
- lambda {
85
- "Method '#{@exp}' called incorrect number of times\n" +
86
- "At least #{@limit} matching #{calls(@limit)} expected\n" +
87
- "#{n} matching #{calls(n)} found\n" +
88
- describe_calls(@exp.mock)
89
- }) { n >= @limit }
90
- end
89
+ validate_count(n) { n >= @limit }
91
90
  end
92
91
 
93
92
  # Human readable description of the validator.
@@ -106,6 +105,10 @@ class FlexMock
106
105
  def eligible?(n)
107
106
  true
108
107
  end
108
+
109
+ def describe_limit
110
+ "At least #{@limit}"
111
+ end
109
112
  end
110
113
 
111
114
  ####################################################################
@@ -114,15 +117,7 @@ class FlexMock
114
117
  class AtMostCountValidator < CountValidator
115
118
  # Validate the method expectation was called at least +n+ times.
116
119
  def validate(n)
117
- @exp.flexmock_location_filter do
118
- FlexMock.framework_adapter.assert_block(
119
- lambda {
120
- "Method '#{@exp}' called incorrect number of times\n" +
121
- "At most #{@limit} matching #{calls(@limit)} expected\n" +
122
- "#{n} matching #{calls(n)} found\n" +
123
- describe_calls(@exp.mock)
124
- }) { n <= @limit }
125
- end
120
+ validate_count(n) { n <= @limit }
126
121
  end
127
122
 
128
123
  # Human readable description of the validator
@@ -130,5 +125,8 @@ class FlexMock
130
125
  ".at_most#{super}"
131
126
  end
132
127
 
128
+ def describe_limit
129
+ "At most #{@limit}"
130
+ end
133
131
  end
134
132
  end
@@ -3,7 +3,7 @@ class FlexMock
3
3
  NUMBERS = [
4
4
  MAJOR = 1,
5
5
  MINOR = 3,
6
- BUILD = 0,
6
+ BUILD = 1,
7
7
  ]
8
8
  end
9
9
 
@@ -2,58 +2,65 @@
2
2
 
3
3
  require 'test/test_setup'
4
4
 
5
- class FlexMock
6
- module StubsAndExpects
7
- def expects(*args)
8
- result = should_receive(*args)
9
- result.at_least.once unless result.call_count_constrained?
10
- result
11
- end
12
- def stubs(*args)
13
- should_receive(*args)
14
- end
15
- end
5
+ # This is an experimental test to see if mock and stub methods can
6
+ # easily be added to a flexmock core. These test are disabled by
7
+ # default, and should be reviewed before something more production
8
+ # oriented is provided.
16
9
 
17
- module MockContainer
18
- alias :mock :flexmock
19
- alias :stub :flexmock
20
- end
10
+ if ENV['TEST_ALIASES']
11
+
12
+ class FlexMock
13
+ module StubsAndExpects
14
+ def expects(*args)
15
+ result = should_receive(*args)
16
+ result.at_least.once unless result.call_count_constrained?
17
+ result
18
+ end
19
+ def stubs(*args)
20
+ should_receive(*args)
21
+ end
22
+ end
21
23
 
22
- include StubsAndExpects
24
+ module MockContainer
25
+ alias :mock :flexmock
26
+ alias :stub :flexmock
27
+ end
23
28
 
24
- class PartialMockProxy
25
29
  include StubsAndExpects
26
- MOCK_METHODS << :stubs << :expects
30
+
31
+ class PartialMockProxy
32
+ include StubsAndExpects
33
+ MOCK_METHODS << :stubs << :expects
34
+ end
27
35
  end
28
- end
29
36
 
30
- class AliasingTest < Test::Unit::TestCase
31
- include FlexMock::TestCase
37
+ class AliasingTest < Test::Unit::TestCase
38
+ include FlexMock::TestCase
32
39
 
33
- def test_mocking
34
- m = mock("a cute dog").expects(:pat).twice.and_return(:woof!).mock
35
- assert_equal :woof!, m.pat
36
- assert_equal :woof!, m.pat
37
- end
40
+ def test_mocking
41
+ m = mock("a cute dog").expects(:pat).twice.and_return(:woof!).mock
42
+ assert_equal :woof!, m.pat
43
+ assert_equal :woof!, m.pat
44
+ end
38
45
 
39
- def test_once_mocking
40
- mock("a cute dog").expects(:pat).and_return(:woof!).mock
41
- end
46
+ def test_once_mocking
47
+ mock("a cute dog").expects(:pat).and_return(:woof!).mock
48
+ end
42
49
 
43
- def test_twice_mocking
44
- m = mock("a cute dog").expects(:pat).and_return(:woof!).twice.mock
45
- assert_raises(assertion_failed_error) { m.flexmock_verify }
46
- end
50
+ def test_twice_mocking
51
+ m = mock("a cute dog").expects(:pat).and_return(:woof!).twice.mock
52
+ assert_raises(assertion_failed_error) { m.flexmock_verify }
53
+ end
47
54
 
48
- def test_stubbing
49
- m = stub("a cute dog").expects(:pat).and_return(:woof!).mock
50
- assert_equal :woof!, m.pat
51
- end
55
+ def test_stubbing
56
+ m = stub("a cute dog").expects(:pat).and_return(:woof!).mock
57
+ assert_equal :woof!, m.pat
58
+ end
52
59
 
53
- def test_partial
54
- obj = Object.new
55
- stub(obj).stubs(:wag).and_return(:tail)
56
- assert_equal :tail, obj.wag
60
+ def test_partial
61
+ obj = Object.new
62
+ stub(obj).stubs(:wag).and_return(:tail)
63
+ assert_equal :tail, obj.wag
64
+ end
57
65
  end
58
66
  end
59
-