test-unit-mock 0.30

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 (10) hide show
  1. data/COPYING +58 -0
  2. data/ChangeLog +262 -0
  3. data/README +203 -0
  4. data/install.rb +85 -0
  5. data/misc/readmecode.rb +125 -0
  6. data/mock.rb +467 -0
  7. data/test-unit-mock.gemspec +20 -0
  8. data/test.rb +327 -0
  9. data/utils.rb +345 -0
  10. metadata +59 -0
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # $Date: 2003/03/04 23:33:31 $
4
+ # Copyright (c) 2000 Masatoshi SEKI
5
+ #
6
+ # install.rb is copyrighted free software by Masatoshi SEKI.
7
+ # You can redistribute it and/or modify it under the same term as Ruby.
8
+
9
+ require 'rbconfig'
10
+ require 'find'
11
+ require 'ftools'
12
+
13
+ include Config
14
+
15
+ class Installer
16
+ protected
17
+ def install(from, to, mode = nil, verbose = false)
18
+ str = "install '#{from}' to '#{to}'"
19
+ str += ", mode=#{mode}" if mode
20
+ puts str if verbose
21
+ end
22
+
23
+ protected
24
+ def makedirs(*dirs)
25
+ for d in dirs
26
+ puts "mkdir #{d}"
27
+ end
28
+ end
29
+
30
+ def initialize(test=false)
31
+ @version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
32
+ @libdir = File.join(CONFIG["libdir"], "ruby", @version)
33
+ @sitelib = find_site_libdir
34
+ @ftools = (test) ? self : File
35
+ end
36
+ public
37
+ attr_reader(:libdir, :sitelib)
38
+
39
+ private
40
+ def find_site_libdir
41
+ site_libdir = $:.find {|x| x =~ /site_ruby$/}
42
+ if !site_libdir
43
+ site_libdir = File.join(@libdir, "site_ruby")
44
+ elsif site_libdir !~ Regexp.quote(@version)
45
+ site_libdir = File.join(site_libdir, @version)
46
+ end
47
+ site_libdir
48
+ end
49
+
50
+ public
51
+ def files_in_dir(dir)
52
+ list = []
53
+ Find.find(dir) do |f|
54
+ list.push(f)
55
+ end
56
+ list
57
+ end
58
+
59
+ public
60
+ def install_files(srcdir, files, destdir=@sitelib)
61
+ path = []
62
+ dir = []
63
+
64
+ for f in files
65
+ next if (f = f[srcdir.length+1..-1]) == nil
66
+ path.push f if File.ftype(File.join(srcdir, f)) == 'file'
67
+ dir |= [ File.dirname(File.join(destdir, f)) ]
68
+ end
69
+ @ftools.makedirs(*dir)
70
+ for f in path
71
+ @ftools.install(File.join(srcdir, f), File.join(destdir, f), nil, true)
72
+ end
73
+ end
74
+
75
+ public
76
+ def install_rb
77
+ intall_files('lib', files_in_dir('lib'))
78
+ end
79
+ end
80
+
81
+ if __FILE__ == $0
82
+ inst = Installer.new(ARGV.shift == '-n')
83
+ inst.install_files( '.', ['./mock.rb'], File::join(inst.sitelib, 'test/unit') )
84
+ end
85
+
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ $LOAD_PATH.unshift ".", ".."
4
+
5
+ require File::join( File::dirname(File::dirname( __FILE__ )), 'utils.rb' )
6
+
7
+ begin
8
+ require 'mock'
9
+ rescue LoadError
10
+ require 'test/unit/mock'
11
+ end
12
+ require 'socket'
13
+ require 'test/unit'
14
+
15
+ # This is just a test to make sure the code in the README works as advertised.
16
+
17
+ class MockTestExperiment < Test::Unit::TestCase
18
+
19
+ def setup
20
+ # Create the mock object
21
+ @mockSocket = Test::Unit::MockObject( TCPSocket ).new
22
+
23
+ # Make the #addr method return three cycling values (which will be repeated
24
+ # when it reaches the end
25
+ @mockSocket.setReturnValues( :addr => [
26
+ ["AF_INET", 23, "localhost", "127.0.0.1"],
27
+ ["AF_INET", 80, "slashdot.org", "66.35.250.150"],
28
+ ["AF_INET", 2401, "helium.ruby-lang.org", "210.251.121.214"],
29
+ ] )
30
+
31
+ # Make the #write and #read methods call a Proc and a Method, respectively
32
+ @mockSocket.setReturnValues( :write => Proc::new {|str| str.length},
33
+ :read => method(:fakeRead) )
34
+
35
+ # Set up the #getsockopt method to return a value based on the arguments
36
+ # given:
37
+ @mockSocket.setReturnValues( :getsockopt => {
38
+ [Socket::SOL_TCP, Socket::TCP_NODELAY] => [0].pack("i_"),
39
+ [Socket::SOL_SOCKET, Socket::SO_REUSEADDR] => [1].pack("i_"),
40
+ } )
41
+
42
+ @mockSocket.setCallOrder( :addr, :getsockopt, :write, :read, :write, :read )
43
+ @mockSocket.strictCallOrder = true
44
+ end
45
+ alias :set_up :setup
46
+
47
+ def teardown
48
+ @mockSocket = nil
49
+ end
50
+ alias :tear_down :teardown
51
+
52
+
53
+ # A method to fake reading from the socket.
54
+ def fakeRead( len )
55
+ return "x" * len
56
+ end
57
+
58
+ # This should pass
59
+ def test_correctorder
60
+ @mockSocket.activate
61
+
62
+ # Call the methods in the correct order
63
+ assert_nothing_raised {
64
+ @mockSocket.addr
65
+ @mockSocket.getsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY )
66
+ @mockSocket.write( "foo" )
67
+ @mockSocket.read( 1024 )
68
+ @mockSocket.write( "bar" )
69
+ @mockSocket.read( 4096 )
70
+ }
71
+
72
+ if $DEBUG
73
+ puts "Call trace:\n " + @mockSocket.callTrace.join("\n ")
74
+ end
75
+
76
+ # Check method call order on the mocked socket
77
+ @mockSocket.verify
78
+ end
79
+
80
+ # This should fail with an incorrect order message
81
+ def test_incorrectorder
82
+ @mockSocket.activate
83
+
84
+ # Call the methods in the correct order
85
+ assert_nothing_raised {
86
+ @mockSocket.addr
87
+ @mockSocket.getsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY )
88
+ @mockSocket.read( 1024 )
89
+ @mockSocket.write( "foo" )
90
+ @mockSocket.write( "bar" )
91
+ @mockSocket.read( 4096 )
92
+ }
93
+
94
+ if $DEBUG
95
+ puts "Call trace:\n " + @mockSocket.callTrace.join("\n ")
96
+ end
97
+
98
+ # Check method call order on the mocked socket
99
+ @mockSocket.verify
100
+ end
101
+
102
+ # This should fail with a 'missing' message
103
+ def test_missingcall
104
+ @mockSocket.activate
105
+
106
+ # Call the methods in the correct order
107
+ assert_nothing_raised {
108
+ @mockSocket.addr
109
+ @mockSocket.getsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY )
110
+ @mockSocket.write( "foo" )
111
+ @mockSocket.read( 1024 )
112
+ @mockSocket.write( "bar" )
113
+ }
114
+
115
+ if $DEBUG
116
+ puts "Call trace:\n " + @mockSocket.callTrace.join("\n ")
117
+ end
118
+
119
+ # Check method call order on the mocked socket
120
+ @mockSocket.verify
121
+ end
122
+
123
+ end
124
+
125
+
data/mock.rb ADDED
@@ -0,0 +1,467 @@
1
+ # Ruby/Mock version 1.0
2
+ #
3
+ # A class for conveniently building mock objects in Test::Unit test cases. It is
4
+ # based on ideas in Ruby/Mock by Nat Pryce <nat.pryce@b13media.com>, which is a
5
+ # class for doing much the same thing for RUnit test cases.
6
+ #
7
+ # == Examples
8
+ #
9
+ # For the examples below, it is assumed that a hypothetical '<tt>Adapter</tt>'
10
+ # class is needed to test whatever class is being tested. It has two instance
11
+ # methods in addition to its initializer: <tt>read</tt>, which takes no
12
+ # arguments and returns data read from the adapted source, and <tt>write</tt>,
13
+ # which takes a String and writes as much as it can to the adapted destination,
14
+ # returning any that is left over.
15
+ #
16
+ # # With the in-place mock-object constructor, you can make an instance of a
17
+ # # one-off anonymous test class:
18
+ # mockAdapter = Test::Unit::MockObject( Adapter ).new
19
+ #
20
+ # # Now set up some return values for the next test:
21
+ # mockAdapter.setReturnValues( :read => "",
22
+ # :write => Proc::new {|data| data[-20,20]} )
23
+ #
24
+ # # Mandate a certain order to the calls
25
+ # mockAdapter.setCallOrder( :read, :read, :read, :write, :read )
26
+ #
27
+ # # Now start the mock object recording interactions with it
28
+ # mockAdapter.activate
29
+ #
30
+ # # Send the adapter to the tested object and run the tests
31
+ # testedObject.setAdapter( mockAdapter )
32
+ # ...
33
+ #
34
+ # # Now check the order of method calls on the mock object against the expected
35
+ # # order.
36
+ # mockAdapter.verify
37
+ #
38
+ # If you require more advanced functionality in your mock class, you can also
39
+ # use the anonymous class returned by the Test::Unit::MockObject factory method
40
+ # as the superclass for your own mockup like this:
41
+ #
42
+ # # Create a mocked adapter class
43
+ # class MockAdapter < Test::Unit::MockObject( Adapter )
44
+ #
45
+ # def initialize
46
+ # super
47
+ # setCallOrder( :read, :read, :read, :write, :read )
48
+ # end
49
+ #
50
+ # def read( *args )
51
+ # @readargs = args
52
+ # super # Call the mocked method to record the call
53
+ # end
54
+ #
55
+ # def write( *args )
56
+ # @writeargs = args
57
+ # super # Call the mocked method to record the call
58
+ # end
59
+ # end
60
+ #
61
+ # == Note
62
+ #
63
+ # All the testing and setup methods in the Test::Unit::Mockup class (the
64
+ # abstract class that new MockObjects inherit from) have two aliases for your
65
+ # convenience:
66
+ #
67
+ # * Each one has a double-underscore alias so that methods which collide with
68
+ # them from the mocked class don't obscure them. Eg.,
69
+ #
70
+ # mockAdapter.__setCallOrder( :read, :read, :read, :write, :read )
71
+ #
72
+ # can be used instead of the call from the example above if the Adapter for
73
+ # some reason already has a 'setCallOrder' instance method.
74
+ #
75
+ # * Non-camelCase versions of the methods are also provided. Eg.,
76
+ #
77
+ # mockAdapter.set_call_order( :read, :read, :read, :write, :read )
78
+ #
79
+ # will work, too. Double-underscored *and* non camelCased aliases are not
80
+ # defined; if anyone complains, I'll add them.
81
+ #
82
+ # == Rcsid
83
+ #
84
+ # $Id: mock.rb,v 1.10 2003/10/01 15:11:40 deveiant Exp $
85
+ #
86
+ # == Authors
87
+ #
88
+ # * Michael Granger <ged@FaerieMUD.org>
89
+ #
90
+ #
91
+ #
92
+
93
+ require 'algorithm/diff'
94
+
95
+ require 'test/unit'
96
+ require 'test/unit/assertions'
97
+
98
+ module Test
99
+ module Unit
100
+
101
+ # The Regexp that matches methods which will not be mocked.
102
+ UnmockedMethods = %r{^(
103
+ __ # __id__, __call__, etc.
104
+ |inspect # Useful as-is for debugging, and hard to fake
105
+ |kind_of\?|is_a\?|instance_of\? # / Can't fake simply -- delegated to the
106
+ |type|class # \ actual underlying class
107
+ |method|send|respond_to\? # These will work fine as-is
108
+ |hash # There's no good way to fake this
109
+ )}x
110
+
111
+ ### An abstract base class that provides the setup and testing methods
112
+ ### to concrete mock objects.
113
+ class Mockup
114
+
115
+ include Test::Unit::Assertions
116
+
117
+ ### Instantiate and return a new mock object after recording the
118
+ ### specified args.
119
+ def initialize( *args )
120
+ @args = args
121
+ @calls = []
122
+ @activated = nil
123
+ @returnValues = Hash::new( true )
124
+ @callOrder = []
125
+ @strictCallOrder = false
126
+ end
127
+
128
+
129
+ #########################################################
130
+ ### F A K E T Y P E - C H E C K I N G M E T H O D S
131
+ #########################################################
132
+
133
+ # Handle #type and #class methods
134
+ alias :__class :class
135
+ def class # :nodoc:
136
+ return __class.mockedClass
137
+ end
138
+ undef_method :type
139
+ alias_method :type, :class
140
+
141
+ # Fake instance_of?, kind_of?, and is_a? with the mocked class
142
+ def instance_of?( klass ) # :nodoc:
143
+ self.class == klass
144
+ end
145
+ def kind_of?( klass ) # :nodoc:
146
+ self.class <= klass
147
+ end
148
+ alias_method :is_a?, :kind_of?
149
+
150
+
151
+ #########################################################
152
+ ### S E T U P M E T H O D S
153
+ #########################################################
154
+
155
+ ### Set the return value for one or more methods. The <tt>hash</tt>
156
+ ### should contain one or more key/value pairs, the key of which is
157
+ ### the symbol which corresponds to the method being configured, and
158
+ ### the value which is a specification of the value to be
159
+ ### returned. More complex returns can be configured with one the
160
+ ### following types of values:
161
+ ###
162
+ ### [<tt>Method</tt> or <tt>Proc</tt>]
163
+ ### A <tt>Method</tt> or <tt>Proc</tt> object will be called with
164
+ ### the arguments given to the method, and whatever it returns
165
+ ### will be used as the return value.
166
+ ### [<tt>Array</tt>]
167
+ ### The first value in the <tt>Array</tt> will be rotated to the
168
+ ### end of the Array and returned.
169
+ ### [<tt>Hash</tt>]
170
+ ### The Array of method arguments will be used as a key, and
171
+ ### whatever the corresponding value in the given Hash is will be
172
+ ### returned.
173
+ ###
174
+ ### Any other value will be returned as-is. To return one of the
175
+ ### above types of objects literally, just wrap it in an Array like
176
+ ### so:
177
+ ###
178
+ ### # Return a literal Proc without calling it:
179
+ ### mockObj.setReturnValues( :meth => [myProc] )
180
+ ###
181
+ ### # Return a literal Array:
182
+ ### mockObj.setReturnValues( :meth => [["an", "array", "of", "stuff"]] )
183
+ def setReturnValues( hash )
184
+ @returnValues.update hash
185
+ end
186
+ alias_method :__setReturnValues, :setReturnValues
187
+ alias_method :set_return_values, :setReturnValues
188
+
189
+
190
+ ### Set up an expected method call order and argument specification
191
+ ### to be checked when #verify is called to the methods specified by
192
+ ### the given <tt>symbols</tt>.
193
+ def setCallOrder( *symbols )
194
+ @callOrder = symbols
195
+ end
196
+ alias_method :__setCallOrder, :setCallOrder
197
+ alias_method :set_call_order, :setCallOrder
198
+
199
+
200
+ ### Set the strict call order flag. When #verify is called, the
201
+ ### methods specified in calls to #setCallOrder will be checked
202
+ ### against the actual methods that were called on the object. If
203
+ ### this flag is set to <tt>true</tt>, any deviation (missing,
204
+ ### misordered, or extra calls) results in a failed assertion. If it
205
+ ### is not set, other method calls may be interspersed between the
206
+ ### calls specified without effect, but a missing or misordered
207
+ ### method still fails.
208
+ def strictCallOrder=( flag )
209
+ @strictCallOrder = true if flag
210
+ end
211
+ alias_method :__strictCallOrder=, :strictCallOrder=
212
+ alias_method :strict_call_order=, :strictCallOrder=
213
+
214
+
215
+ ### Returns true if strict call order checking is enabled.
216
+ def strictCallOrder?
217
+ @strictCallOrder
218
+ end
219
+ alias_method :__strictCallOrder?, :strictCallOrder?
220
+ alias_method :strict_call_order?, :strictCallOrder?
221
+
222
+
223
+ #########################################################
224
+ ### T E S T I N G M E T H O D S
225
+ #########################################################
226
+
227
+ ### Returns an array of Strings describing, in cronological order,
228
+ ### what method calls were registered with the object.
229
+ def callTrace
230
+ return [] unless @activated
231
+ @calls.collect {|call|
232
+ "%s( %s ) at %0.5f seconds from %s" % [
233
+ call[:method].to_s,
234
+ call[:args].collect {|arg| arg.inspect}.join(","),
235
+ call[:time] - @activated,
236
+ call[:caller][0]
237
+ ]
238
+ }
239
+ end
240
+ alias_method :__callTrace, :callTrace
241
+ alias_method :call_trace, :callTrace
242
+
243
+
244
+ ### Returns an array of Strings describing, in cronological order,
245
+ ### what method calls were registered with the object along with a
246
+ ### full stacktrace for each call.
247
+ def fullCallTrace
248
+ return [] unless @activated
249
+ @calls.collect {|call|
250
+ "%s( %s ) at %0.5f seconds. Called from %s\n\t%s" % [
251
+ call[:method].to_s,
252
+ call[:args].collect {|arg| arg.inspect}.join(","),
253
+ call[:time] - @activated,
254
+ call[:caller][0],
255
+ call[:caller][1..-1].join("\n\t"),
256
+ ]
257
+ }
258
+ end
259
+ alias_method :__fullCallTrace, :fullCallTrace
260
+ alias_method :full_call_trace, :fullCallTrace
261
+
262
+
263
+ ### Turn on call registration -- begin testing.
264
+ def activate
265
+ raise "Already activated!" if @activated
266
+ self.__clear
267
+ @activated = Time::now
268
+ end
269
+ alias_method :__activate, :activate
270
+
271
+
272
+ ### Verify the registered required methods were called with the
273
+ ### specified args
274
+ def verify
275
+ raise "Cannot verify a mock object that has never been "\
276
+ "activated." unless @activated
277
+ return true if @callOrder.empty?
278
+
279
+ actualCallOrder = @calls.collect {|call| call[:method]}
280
+ diff = Diff::diff( @callOrder, actualCallOrder )
281
+
282
+ # In strict mode, any differences are failures
283
+ if @strictCallOrder
284
+ msg = "{Message}"
285
+ assert_block( msg ) {
286
+ unless diff.empty?
287
+ msg.replace __makeCallOrderFailMsg(*diff[0])
288
+ end
289
+ diff.empty?
290
+ }
291
+
292
+ # In non-strict mode, only methods missing (:-) from the call
293
+ # order are failures.
294
+ else
295
+ msg = "{Message}"
296
+ assert_block( msg ) {
297
+ missingDiff = diff.find {|d| d[0] == :-}
298
+ unless missingDiff.nil?
299
+ msg.replace __makeCallOrderFailMsg( *missingDiff )
300
+ end
301
+ missingDiff.nil?
302
+ }
303
+ end
304
+ end
305
+ alias_method :__verify, :verify
306
+
307
+
308
+ ### Deactivate the object without doing call order checks and clear
309
+ ### the call list, but keep its configuration.
310
+ def clear
311
+ @calls.clear
312
+ @activated = nil
313
+ end
314
+ alias_method :__clear, :clear
315
+
316
+
317
+ ### Clear the call list and call order, unset any return values, and
318
+ ### deactivate the object without checking for conformance to the
319
+ ### call order.
320
+ def reset
321
+ self.__clear
322
+ @callOrder.clear
323
+ @returnValues.clear
324
+ end
325
+ alias_method :__reset, :reset
326
+
327
+
328
+ #########
329
+ protected
330
+ #########
331
+
332
+ ### Register a call to the faked method designated by <tt>sym</tt>
333
+ ### if the object is activated, and return a value as configured by
334
+ ### #setReturnValues given the specified <tt>args</tt>.
335
+ def __mockRegisterCall( sym, *args, &block )
336
+ if @activated
337
+ @calls.push({
338
+ :method => sym,
339
+ :args => args,
340
+ :time => Time::now,
341
+ :caller => caller(2),
342
+ })
343
+ end
344
+
345
+ rval = @returnValues[ sym ]
346
+ case rval
347
+ when Method, Proc
348
+ return rval.call( *args, &block )
349
+
350
+ when Array
351
+ return rval.push( rval.shift )[-1]
352
+
353
+ when Hash
354
+ return rval[ args ]
355
+
356
+ else
357
+ return rval
358
+ end
359
+ end
360
+ alias_method :__mock_register_call, :__mockRegisterCall
361
+
362
+
363
+ ### Build and return an error message for a call-order verification
364
+ ### failure. The expected arguments are those returned in an element
365
+ ### of the Array that is returned from Diff::diff.
366
+ def __makeCallOrderFailMsg( action, position, elements )
367
+ case action
368
+
369
+ # "Extra" method/s
370
+ when :+
371
+ extraCall = @calls[ position ]
372
+ return "Call order assertion failed: Unexpected method %s "\
373
+ "called from %s at %0.5f" %
374
+ [ extraCall[:method].inspect,
375
+ extraCall[:caller][0],
376
+ extraCall[:time] - @activated ]
377
+
378
+ when :-
379
+ # If there is a call in the position specified, it was a
380
+ # misordered or extra call. If not, there was a missing
381
+ # call.
382
+ missingCall = @callOrder[ position ]
383
+ if extraCall = @calls[ position ]
384
+ return "Call order assertion failed: Expected call to %s, "\
385
+ "but got call to %s from %s at %0.5f instead" %
386
+ [ missingCall.inspect,
387
+ extraCall[:method].inspect,
388
+ extraCall[:caller][0],
389
+ extraCall[:time] - @activated ]
390
+ else
391
+ return "Call order assertion failed: Missing call to %s." %
392
+ missingCall.inspect
393
+ end
394
+
395
+ else
396
+ return "Unknown diff action '#{action.inspect}'"
397
+ end
398
+ end
399
+ alias_method :__make_call_order_fail_msg, :__makeCallOrderFailMsg
400
+
401
+
402
+ end
403
+
404
+
405
+ ### Factory method for creating semi-functional mock objects given the
406
+ ### class which is to be mocked. It looks like a constant for purposes
407
+ ### of syntactic sugar.
408
+ def self::MockObject( klass )
409
+ mockup = Class::new( Mockup )
410
+ mockup.instance_eval do @mockedClass = klass end
411
+
412
+ ### Provide an accessor to class instance var that holds the class
413
+ ### object we're faking
414
+ class << mockup
415
+
416
+ # The actual class being mocked
417
+ attr_reader :mockedClass
418
+
419
+ ### Propagate the mocked class ivar to derivatives so it can be
420
+ ### called like:
421
+ ### class MockFoo < Test::Unit::MockObject( RealClass )
422
+ def inherited( subclass )
423
+ mc = self.mockedClass
424
+ subclass.instance_eval do @mockedClass = mc end
425
+ end
426
+ end
427
+
428
+ # Build method definitions for all the mocked class's instance
429
+ # methods, as well as those given to it by its superclasses, since
430
+ # we're not really inheriting from it.
431
+ imethods = klass.instance_methods(true).collect {|name|
432
+ next if name =~ UnmockedMethods
433
+
434
+ # Figure out the argument list
435
+ argCount = klass.instance_method( name ).arity
436
+ optionalArgs = false
437
+
438
+ if argCount < 0
439
+ optionalArgs = true
440
+ argCount = (argCount+1).abs
441
+ end
442
+
443
+ args = []
444
+ argCount.times do |n| args << "arg#{n+1}" end
445
+ args << "*optionalArgs" if optionalArgs
446
+
447
+ # Build a method definition. Some methods need special
448
+ # declarations.
449
+ case name.intern
450
+ when :initialize
451
+ "def initialize( %s ) ; super ; end" % args.join(',')
452
+
453
+ else
454
+ "def %s( %s ) ; self.__mockRegisterCall(%s) ; end" %
455
+ [ name, args.join(','), [":#{name}", *args].join(',') ]
456
+ end
457
+ }
458
+
459
+ # Now add the instance methods to the mockup class
460
+ mockup.class_eval imethods.join( "\n" )
461
+ return mockup
462
+ end
463
+
464
+ end # module Unit
465
+ end # module Test
466
+
467
+