flexmock 1.3.0 → 1.3.1

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