flexmock 0.5.1 → 0.6.0
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.
- data/CHANGELOG +10 -1
- data/README +390 -209
- data/Rakefile +31 -10
- data/doc/GoogleExample.rdoc +275 -0
- data/doc/releases/flexmock-0.6.0.rdoc +136 -0
- data/lib/flexmock.rb +3 -1160
- data/lib/flexmock/argument_matchers.rb +57 -0
- data/lib/flexmock/argument_types.rb +42 -0
- data/lib/flexmock/base.rb +22 -0
- data/lib/flexmock/composite.rb +10 -0
- data/lib/flexmock/core.rb +206 -0
- data/lib/flexmock/core_class_methods.rb +92 -0
- data/lib/flexmock/default_framework_adapter.rb +31 -0
- data/lib/flexmock/expectation.rb +334 -0
- data/lib/flexmock/expectation_director.rb +59 -0
- data/lib/flexmock/mock_container.rb +159 -0
- data/lib/flexmock/noop.rb +13 -0
- data/lib/flexmock/partial_mock.rb +226 -0
- data/lib/flexmock/recorder.rb +71 -0
- data/lib/flexmock/rspec.rb +34 -0
- data/lib/flexmock/test_unit.rb +32 -0
- data/lib/flexmock/test_unit_integration.rb +53 -0
- data/lib/flexmock/validators.rb +77 -0
- data/test/rspec_integration/integration_spec.rb +36 -0
- data/test/test_container_methods.rb +119 -0
- data/test/test_default_framework_adapter.rb +39 -0
- data/test/test_example.rb +1 -1
- data/test/test_extended_should_receive.rb +63 -0
- data/test/test_mock.rb +1 -1
- data/test/test_naming.rb +1 -1
- data/test/{test_any_instance.rb → test_new_instances.rb} +15 -8
- data/test/{test_stubbing.rb → test_partial_mock.rb} +44 -44
- data/test/test_record_mode.rb +1 -1
- data/test/test_samples.rb +6 -8
- data/test/test_should_receive.rb +7 -3
- data/test/test_tu_integration.rb +1 -1
- data/test/test_unit_integration/test_auto_test_unit.rb +34 -0
- metadata +30 -5
- data/test/test_class_interception.rb +0 -140
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
|
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 'flexmock/noop'
|
13
|
+
|
14
|
+
class FlexMock
|
15
|
+
####################################################################
|
16
|
+
# Match any object
|
17
|
+
class AnyMatcher
|
18
|
+
def ===(target)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
def inspect
|
22
|
+
"ANY"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
####################################################################
|
27
|
+
# Match only things that are equal.
|
28
|
+
class EqualMatcher
|
29
|
+
def initialize(obj)
|
30
|
+
@obj = obj
|
31
|
+
end
|
32
|
+
def ===(target)
|
33
|
+
@obj == target
|
34
|
+
end
|
35
|
+
def inspect
|
36
|
+
"==(#{@obj.inspect})"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ANY = AnyMatcher.new
|
41
|
+
|
42
|
+
####################################################################
|
43
|
+
# Match only things where the block evaluates to true.
|
44
|
+
class ProcMatcher
|
45
|
+
def initialize(&block)
|
46
|
+
@block = block
|
47
|
+
end
|
48
|
+
def ===(target)
|
49
|
+
@block.call(target)
|
50
|
+
end
|
51
|
+
def inspect
|
52
|
+
"on{...}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
|
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 'flexmock/argument_matchers'
|
13
|
+
|
14
|
+
class FlexMock
|
15
|
+
|
16
|
+
####################################################################
|
17
|
+
# Include this module in your test class if you wish to use the +eq+
|
18
|
+
# and +any+ argument matching methods without a prefix. (Otherwise
|
19
|
+
# use <tt>FlexMock.any</tt> and <tt>FlexMock.eq(obj)</tt>.
|
20
|
+
#
|
21
|
+
module ArgumentTypes
|
22
|
+
# Return an argument matcher that matches any argument.
|
23
|
+
def any
|
24
|
+
ANY
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return an argument matcher that only matches things equal to
|
28
|
+
# (==) the given object.
|
29
|
+
def eq(obj)
|
30
|
+
EqualMatcher.new(obj)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return an argument matcher that matches any object, that when
|
34
|
+
# passed to the supplied block, will cause the block to return
|
35
|
+
# true.
|
36
|
+
def on(&block)
|
37
|
+
ProcMatcher.new(&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
extend ArgumentTypes
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
|
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 'flexmock/core'
|
13
|
+
|
14
|
+
require 'flexmock/default_framework_adapter'
|
15
|
+
require 'flexmock/expectation_director'
|
16
|
+
require 'flexmock/expectation'
|
17
|
+
require 'flexmock/argument_matchers'
|
18
|
+
require 'flexmock/argument_types'
|
19
|
+
require 'flexmock/validators'
|
20
|
+
require 'flexmock/recorder'
|
21
|
+
require 'flexmock/mock_container'
|
22
|
+
require 'flexmock/partial_mock'
|
@@ -0,0 +1,206 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
|
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 'flexmock/composite'
|
13
|
+
|
14
|
+
######################################################################
|
15
|
+
# FlexMock is a flexible mock object framework for supporting testing.
|
16
|
+
#
|
17
|
+
# FlexMock has a simple interface that's easy to remember, and leaves
|
18
|
+
# the hard stuff to all those other mock object implementations.
|
19
|
+
#
|
20
|
+
# Basic Usage:
|
21
|
+
#
|
22
|
+
# m = flexmock("name")
|
23
|
+
# m.should_receive(:upcase).with("stuff").
|
24
|
+
# and_return("STUFF")
|
25
|
+
# m.should_receive(:downcase).with(String).
|
26
|
+
# and_return { |s| s.downcase }.once
|
27
|
+
#
|
28
|
+
# With Test::Unit Integration:
|
29
|
+
#
|
30
|
+
# class TestSomething < Test::Unit::TestCase
|
31
|
+
# include FlexMock::TestCase
|
32
|
+
#
|
33
|
+
# def test_something
|
34
|
+
# m = flexmock("name")
|
35
|
+
# m.should_receive(:hi).and_return("Hello")
|
36
|
+
# m.hi
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# Note: When using Test::Unit integeration, don't forget to include
|
41
|
+
# FlexMock::TestCase. Also, if you override +teardown+, make sure you
|
42
|
+
# call +super+.
|
43
|
+
#
|
44
|
+
class FlexMock
|
45
|
+
attr_reader :mock_name, :mock_groups
|
46
|
+
attr_accessor :mock_current_order, :mock_container
|
47
|
+
|
48
|
+
# Create a FlexMock object with the given name. The name is used in
|
49
|
+
# error messages.
|
50
|
+
def initialize(name="unknown")
|
51
|
+
@mock_name = name
|
52
|
+
@expectations = Hash.new
|
53
|
+
@allocated_order = 0
|
54
|
+
@mock_current_order = 0
|
55
|
+
@mock_container = nil
|
56
|
+
@mock_groups = {}
|
57
|
+
@ignore_missing = false
|
58
|
+
@verified = false
|
59
|
+
end
|
60
|
+
|
61
|
+
# Handle all messages denoted by +sym+ by calling the given block
|
62
|
+
# and passing any parameters to the block. If we know exactly how
|
63
|
+
# many calls are to be made to a particular method, we may check
|
64
|
+
# that by passing in the number of expected calls as a second
|
65
|
+
# paramter.
|
66
|
+
def mock_handle(sym, expected_count=nil, &block) # :nodoc:
|
67
|
+
self.should_receive(sym).times(expected_count).returns(&block)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Verify that each method that had an explicit expected count was
|
71
|
+
# actually called that many times.
|
72
|
+
def mock_verify
|
73
|
+
return if @verified
|
74
|
+
@verified = true
|
75
|
+
mock_wrap do
|
76
|
+
@expectations.each do |sym, handler|
|
77
|
+
handler.mock_verify
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Teardown and infrastructure setup for this mock.
|
83
|
+
def mock_teardown
|
84
|
+
end
|
85
|
+
|
86
|
+
# Allocation a new order number from the mock.
|
87
|
+
def mock_allocate_order
|
88
|
+
@auto_allocate = true
|
89
|
+
@allocated_order += 1
|
90
|
+
end
|
91
|
+
|
92
|
+
# Ignore all undefined (missing) method calls.
|
93
|
+
def should_ignore_missing
|
94
|
+
@ignore_missing = true
|
95
|
+
end
|
96
|
+
alias mock_ignore_missing should_ignore_missing
|
97
|
+
|
98
|
+
# Handle missing methods by attempting to look up a handler.
|
99
|
+
def method_missing(sym, *args, &block)
|
100
|
+
mock_wrap do
|
101
|
+
if handler = @expectations[sym]
|
102
|
+
args << block if block_given?
|
103
|
+
handler.call(*args)
|
104
|
+
else
|
105
|
+
super(sym, *args, &block) unless @ignore_missing
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Save the original definition of respond_to? for use a bit later.
|
111
|
+
alias mock_respond_to? respond_to?
|
112
|
+
|
113
|
+
# Override the built-in respond_to? to include the mocked methods.
|
114
|
+
def respond_to?(sym)
|
115
|
+
super || (@expectations[sym] ? true : @ignore_missing)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Override the built-in +method+ to include the mocked methods.
|
119
|
+
def method(sym)
|
120
|
+
@expectations[sym] || super
|
121
|
+
rescue NameError => ex
|
122
|
+
if @ignore_missing
|
123
|
+
proc { }
|
124
|
+
else
|
125
|
+
raise ex
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# :call-seq:
|
130
|
+
# mock.should_receive(:method_name)
|
131
|
+
# mock.should_receive(:method1, method2, ...)
|
132
|
+
# mock.should_receive(:meth1 => result1, :meth2 => result2, ...)
|
133
|
+
#
|
134
|
+
# Declare that the mock object should receive a message with the given name.
|
135
|
+
#
|
136
|
+
# If more than one method name is given, then the mock object should expect
|
137
|
+
# to receive all the listed melthods. If a hash of method name/value pairs
|
138
|
+
# is given, then the each method will return the associated result. Any
|
139
|
+
# expectations applied to the result of +should_receive+ will be applied to
|
140
|
+
# all the methods defined in the argument list.
|
141
|
+
#
|
142
|
+
# An expectation object for the method name is returned as the result of
|
143
|
+
# this method. Further expectation constraints can be added by chaining to
|
144
|
+
# the result.
|
145
|
+
#
|
146
|
+
# See Expectation for a list of declarators that can be used.
|
147
|
+
#
|
148
|
+
def should_receive(*args)
|
149
|
+
FlexMock.should_receive(args) do |sym|
|
150
|
+
@expectations[sym] ||= ExpectationDirector.new(sym)
|
151
|
+
result = Expectation.new(self, sym)
|
152
|
+
@expectations[sym] << result
|
153
|
+
override_existing_method(sym) if mock_respond_to?(sym)
|
154
|
+
result
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Declare that the mock object should expect methods by providing a
|
159
|
+
# recorder for the methods and having the user invoke the expected
|
160
|
+
# methods in a block. Further expectations may be applied the
|
161
|
+
# result of the recording call.
|
162
|
+
#
|
163
|
+
# Example Usage:
|
164
|
+
#
|
165
|
+
# mock.should_expect do |record|
|
166
|
+
# record.add(Integer, 4) { |a, b|
|
167
|
+
# a + b
|
168
|
+
# }.at_least.once
|
169
|
+
#
|
170
|
+
def should_expect
|
171
|
+
yield Recorder.new(self)
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
# Wrap a block of code so the any assertion errors are wrapped so
|
177
|
+
# that the mock name is added to the error message .
|
178
|
+
def mock_wrap(&block)
|
179
|
+
yield
|
180
|
+
rescue FlexMock.framework_adapter.assertion_failed_error => ex
|
181
|
+
raise FlexMock.framework_adapter.assertion_failed_error,
|
182
|
+
"in mock '#{@mock_name}': #{ex.message}",
|
183
|
+
ex.backtrace
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# Override the existing definition of method +sym+ in the mock.
|
188
|
+
# Most methods depend on the method_missing trick to be invoked.
|
189
|
+
# However, if the method already exists, it will not call
|
190
|
+
# method_missing. This method defines a singleton method on the
|
191
|
+
# mock to explicitly invoke the method_missing logic.
|
192
|
+
def override_existing_method(sym)
|
193
|
+
sclass.class_eval <<-EOS
|
194
|
+
def #{sym}(*args, &block)
|
195
|
+
method_missing(:#{sym}, *args, &block)
|
196
|
+
end
|
197
|
+
EOS
|
198
|
+
end
|
199
|
+
|
200
|
+
# Return the singleton class of the mock object.
|
201
|
+
def sclass
|
202
|
+
class << self; self; end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
require 'flexmock/core_class_methods'
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
|
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 'flexmock/noop'
|
13
|
+
|
14
|
+
class FlexMock
|
15
|
+
class << self
|
16
|
+
attr_reader :framework_adapter
|
17
|
+
|
18
|
+
# :call-seq:
|
19
|
+
# should_receive(args) { |symbol| ... }
|
20
|
+
#
|
21
|
+
# This method provides common handling for the various should_receive
|
22
|
+
# argument lists. It sorts out the differences between symbols, arrays and
|
23
|
+
# hashes, and identifies the method names specified by each. As each
|
24
|
+
# method name is identified, create a mock expectation for it using the
|
25
|
+
# supplied block.
|
26
|
+
def should_receive(args) # :nodoc:
|
27
|
+
result = CompositeExpectation.new
|
28
|
+
args.each do |arg|
|
29
|
+
case arg
|
30
|
+
when Hash
|
31
|
+
arg.each do |k,v|
|
32
|
+
result.add(yield(k.to_sym).and_return(v))
|
33
|
+
end
|
34
|
+
when Symbol, String
|
35
|
+
result.add(yield(arg.to_sym))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
# Class method to make sure that verify is called at the end of a
|
42
|
+
# test. One mock object will be created for each name given to
|
43
|
+
# the use method. The mocks will be passed to the block as
|
44
|
+
# arguments. If no names are given, then a single anonymous mock
|
45
|
+
# object will be created.
|
46
|
+
#
|
47
|
+
# At the end of the use block, each mock object will be verified
|
48
|
+
# to make sure the proper number of calls have been made.
|
49
|
+
#
|
50
|
+
# Usage:
|
51
|
+
#
|
52
|
+
# FlexMock.use("name") do |mock| # Creates a mock named "name"
|
53
|
+
# mock.should_receive(:meth).
|
54
|
+
# returns(0).once
|
55
|
+
# end # mock is verified here
|
56
|
+
#
|
57
|
+
# NOTE: If you include FlexMock::TestCase into your test case
|
58
|
+
# file, you can create mocks that will be automatically verified in
|
59
|
+
# the test teardown by using the +flexmock+ method.
|
60
|
+
#
|
61
|
+
def use(*names)
|
62
|
+
names = ["unknown"] if names.empty?
|
63
|
+
got_excecption = false
|
64
|
+
mocks = names.collect { |n| new(n) }
|
65
|
+
yield(*mocks)
|
66
|
+
rescue Exception => ex
|
67
|
+
got_exception = true
|
68
|
+
raise
|
69
|
+
ensure
|
70
|
+
mocks.each do |mock|
|
71
|
+
mock.mock_verify unless got_exception
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Class method to format a method name and argument list as a nice
|
76
|
+
# looking string.
|
77
|
+
def format_args(sym, args) # :nodoc:
|
78
|
+
if args
|
79
|
+
"#{sym}(#{args.collect { |a| a.inspect }.join(', ')})"
|
80
|
+
else
|
81
|
+
"#{sym}(*args)"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Check will assert the block returns true. If it doesn't, an
|
86
|
+
# assertion failure is triggered with the given message.
|
87
|
+
def check(msg, &block) # :nodoc:
|
88
|
+
FlexMock.framework_adapter.assert_block(msg, &block)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#---
|
4
|
+
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
|
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 'flexmock/noop'
|
13
|
+
|
14
|
+
class FlexMock
|
15
|
+
class DefaultFrameworkAdapter
|
16
|
+
def assert_block(msg, &block)
|
17
|
+
unless yield
|
18
|
+
fail assertion_failed_error, msg
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_equal(a, b, msg=nil)
|
23
|
+
assert_block(msg || "Expected equal") { a == b }
|
24
|
+
end
|
25
|
+
|
26
|
+
class AssertionFailedError < StandardError; end
|
27
|
+
def assertion_failed_error
|
28
|
+
AssertionFailedError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|