test_internals 0.0.2 → 1.0.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/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/README +61 -13
- data/lib/test_internals/test_case.rb +374 -220
- data/lib/test_internals/{app_state.rb → test_internals.rb} +4 -4
- data/lib/test_internals.rb +2 -3
- data/test_internals.gemspec +10 -7
- metadata +15 -12
- data/lib/test_internals/kernel.rb +0 -42
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
app_mode (
|
4
|
+
app_mode (1.0.1)
|
5
5
|
rake (0.8.7)
|
6
|
-
rake_tasks (0.0.
|
6
|
+
rake_tasks (0.0.4)
|
7
7
|
rake (~> 0.8.7)
|
8
8
|
|
9
9
|
PLATFORMS
|
10
10
|
ruby
|
11
11
|
|
12
12
|
DEPENDENCIES
|
13
|
-
app_mode (~> 0.0
|
13
|
+
app_mode (~> 1.0.0)
|
14
14
|
rake_tasks (~> 0.0.1)
|
data/README
CHANGED
@@ -1,15 +1,9 @@
|
|
1
1
|
== Welcome to TestInternals
|
2
2
|
|
3
|
-
TestInternals patches Test::Unit::TestCase to allow
|
4
|
-
as well as variables.
|
5
|
-
|
6
|
-
|
7
|
-
that specific parameter values were sent to a method.
|
8
|
-
|
9
|
-
It will also prevent the application from stopping tests if exit is called.
|
10
|
-
assert_alive and assert_dead have been included to assist in testing.
|
11
|
-
|
12
|
-
There are also a number of assertions that have been added.
|
3
|
+
TestInternals patches Test::Unit::TestCase to allow
|
4
|
+
testing of private methods, as well as variables. The stack trace
|
5
|
+
is also available, including the ability to check that specific
|
6
|
+
parameters were sent to a method. This results in cotton candy goodness for all.
|
13
7
|
|
14
8
|
== Getting Started
|
15
9
|
|
@@ -17,14 +11,68 @@ There are also a number of assertions that have been added.
|
|
17
11
|
|
18
12
|
gem install test_internals
|
19
13
|
|
20
|
-
2. Require the gem in your
|
14
|
+
2. Require the gem in your Gemfile:
|
21
15
|
|
22
|
-
gem 'test_internals', '~> 0.0
|
16
|
+
gem 'test_internals', '~> 1.0.0'
|
23
17
|
|
24
|
-
3. Require the gem wherever you need
|
18
|
+
3. Require the gem wherever you need to use it:
|
25
19
|
|
26
20
|
require 'test_internals'
|
27
21
|
|
22
|
+
== Overriding Default Behavior
|
23
|
+
|
24
|
+
To call methods that enable functionality or to override
|
25
|
+
variable settings, add an initialize method to your test
|
26
|
+
and call the desired method, calling super after:
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
expose_all_variables
|
30
|
+
expose_stack
|
31
|
+
expose_class_methods
|
32
|
+
expose_instance_methods
|
33
|
+
@class = MyClass
|
34
|
+
init_object(param1, param2, ...)
|
35
|
+
# ...
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
NOTE: If it is not included in this example,
|
40
|
+
it is not expected to be used in the initialize method.
|
41
|
+
|
42
|
+
== Instance Variables
|
43
|
+
|
44
|
+
=== @class
|
45
|
+
|
46
|
+
The @class variable, will exist for every test.
|
47
|
+
The class is inferred from the name of the test.
|
48
|
+
For example, a class named MyClass
|
49
|
+
is expected to be tested by a class named MyClassTest.
|
50
|
+
|
51
|
+
The default behavior may be overridden by specifying the class
|
52
|
+
in the initialize method of your test as shown above.
|
53
|
+
|
54
|
+
=== @obj
|
55
|
+
|
56
|
+
This is only non-nil if init_object has been called in the initialize method
|
57
|
+
(and the class responds to the :new method).
|
58
|
+
See rdoc for additional details.
|
59
|
+
|
60
|
+
== Additional Notes
|
61
|
+
|
62
|
+
* Methods marked protected are intended to be used by sub-classes.
|
63
|
+
|
64
|
+
* Methods marked private are intended to be used only by the class itself
|
65
|
+
and are NOT intended for use in sub-classes.
|
66
|
+
If they are, results may be unpredictable.
|
67
|
+
|
68
|
+
* When send_to_class or send_to_object are called, the calls are wrapped such
|
69
|
+
that output is captured and not sent to the console.
|
70
|
+
The output may be retrieved via the following methods:
|
71
|
+
|
72
|
+
out #=> output to stdout
|
73
|
+
err #=> output to stderr
|
74
|
+
real_finis #=> An array [out, err]
|
75
|
+
|
28
76
|
== Additional Documentation
|
29
77
|
|
30
78
|
rake rdoc:app
|
@@ -34,16 +34,18 @@
|
|
34
34
|
|
35
35
|
# Monkey patch Test::Unit::TestCase to make it do cool stuff.
|
36
36
|
Test::Unit::TestCase.class_eval do
|
37
|
+
include TestInternals
|
38
|
+
|
37
39
|
# Since this is in a class_eval, instance methods need to be wrapped up
|
38
40
|
# in class_variable_set or ruby will throw warnings.
|
39
41
|
|
40
42
|
# Indicates whether the class has already been initialized.
|
41
43
|
# This combined with @@class_name prevents duplicate patching.
|
42
|
-
class_variable_set(:@@initialized,
|
44
|
+
class_variable_set(:@@initialized, nil)
|
43
45
|
|
44
46
|
# Keeps track of the class that has most recently been initialized.
|
45
47
|
# This combined with @@initialized prevents duplicate patching.
|
46
|
-
class_variable_set(:@@class_name,
|
48
|
+
class_variable_set(:@@class_name, nil)
|
47
49
|
|
48
50
|
# Initializes the class
|
49
51
|
# and exposes private methods and variables of the class that is being tested.
|
@@ -51,19 +53,26 @@ Test::Unit::TestCase.class_eval do
|
|
51
53
|
# Call initialize on the superclass.
|
52
54
|
super
|
53
55
|
|
54
|
-
@obj
|
56
|
+
@obj = nil
|
57
|
+
@class = nil unless defined?(@class)
|
58
|
+
|
59
|
+
@init_object = nil unless defined?(@init_object)
|
60
|
+
@init_object_params = nil unless defined?(@init_object_params)
|
61
|
+
|
62
|
+
@expose_instance_methods = nil unless defined?(@expose_instance_methods)
|
63
|
+
@expose_class_methods = nil unless defined?(@expose_class_methods)
|
64
|
+
@expose_variables = nil unless defined?(@expose_variables)
|
65
|
+
@expose_stack = nil unless defined?(@expose_stack)
|
55
66
|
|
56
67
|
reset_io
|
57
|
-
reset_trace
|
58
68
|
|
59
69
|
# This block ensures that tests still work if there is not a class that
|
60
70
|
# corresponds with the test file/class.
|
61
|
-
@class = nil
|
62
71
|
begin
|
63
72
|
# Get the class that is being tested.
|
64
73
|
# Assume that the name of the class is found by removing 'Test'
|
65
74
|
# from the test class.
|
66
|
-
@class
|
75
|
+
@class ||= Kernel.const_get(self.class.name.gsub(/Test$/, ''))
|
67
76
|
@@initialized = ((@class.name == @@class_name) && @@initialized)
|
68
77
|
@@class_name = @class.name
|
69
78
|
rescue
|
@@ -72,34 +81,41 @@ Test::Unit::TestCase.class_eval do
|
|
72
81
|
end
|
73
82
|
|
74
83
|
# Only patch if this code has not yet been run.
|
75
|
-
if !@@initialized
|
76
|
-
set_instance_method_wrappers
|
84
|
+
if !@@initialized
|
85
|
+
set_instance_method_wrappers if @expose_stack
|
77
86
|
|
78
87
|
# Expose private class methods.
|
79
88
|
# We will only expose the methods we are responsible for creating.
|
80
89
|
# (i.e. subtracting the superclass's private methods)
|
81
90
|
expose_private_methods(:class,
|
82
91
|
@class.private_methods -
|
83
|
-
@class.superclass.private_methods)
|
92
|
+
@class.superclass.private_methods) if @expose_class_methods
|
84
93
|
|
85
94
|
# Expose private instance methods.
|
86
95
|
# We will only expose the methods we are responsible for creating.
|
87
96
|
# (i.e. subtracting the superclass's private methods)
|
88
97
|
expose_private_methods(:instance,
|
89
98
|
@class.private_instance_methods -
|
90
|
-
@class.superclass.private_instance_methods)
|
99
|
+
@class.superclass.private_instance_methods) if @expose_instance_methods
|
91
100
|
|
92
101
|
# Expose variables.
|
93
102
|
# Requires that variables are assigned to in the constructor.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
103
|
+
if @expose_variables
|
104
|
+
init_with_defaults if new_object_on_init?
|
105
|
+
instance_variable_list = @obj.nil? ? [] : @obj.instance_variables
|
106
|
+
expose_variables @class.class_variables + instance_variable_list
|
107
|
+
end
|
98
108
|
|
99
109
|
# Indicate that this code has been run.
|
100
110
|
@@initialized = true
|
101
111
|
end
|
102
112
|
|
113
|
+
# This is potentially called a second time so that the object will
|
114
|
+
# include any goodies we have added here.
|
115
|
+
init_with_defaults if new_object_on_init?
|
116
|
+
|
117
|
+
reset_trace
|
118
|
+
|
103
119
|
# If initializing the class with @class.new above kills the app,
|
104
120
|
# we need to set it back to running, but we want to do this regardless.
|
105
121
|
reset_app_state
|
@@ -110,194 +126,149 @@ Test::Unit::TestCase.class_eval do
|
|
110
126
|
# Tracing is set up here so that it is only running during tests.
|
111
127
|
#
|
112
128
|
# If you want to disable tracing, simply override the setup method
|
113
|
-
# without calling super.
|
129
|
+
# without calling super.
|
114
130
|
def setup
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
131
|
+
if @expose_stack
|
132
|
+
set_trace_func proc { |event, file, line, id, binding, class_name|
|
133
|
+
if class_name == @class and
|
134
|
+
@stack_trace.last != {:class => class_name.name, :method => id}
|
135
|
+
@stack_trace << {
|
136
|
+
:class => class_name.name,
|
137
|
+
:method => id,
|
138
|
+
}
|
139
|
+
end
|
140
|
+
}
|
141
|
+
end
|
124
142
|
end
|
125
143
|
|
126
144
|
# Clean up after each test.
|
127
|
-
#
|
128
|
-
# If you disable tracing, it would be good form to override this method
|
129
|
-
# as well without calling super.
|
130
145
|
def teardown
|
131
|
-
set_trace_func nil
|
146
|
+
set_trace_func nil if @expose_stack
|
132
147
|
end
|
133
148
|
|
134
149
|
############################################################################
|
135
|
-
|
150
|
+
protected
|
136
151
|
############################################################################
|
137
152
|
|
153
|
+
# Protected methods are intended for use in this class and/or sub-classes.
|
154
|
+
|
138
155
|
############################################################################
|
139
|
-
#
|
156
|
+
# @obj and @class-related methods
|
140
157
|
############################################################################
|
141
158
|
|
142
|
-
#
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
return result
|
153
|
-
end
|
154
|
-
end
|
159
|
+
# Creates a new instance of the class using the arguments that are passed in.
|
160
|
+
#
|
161
|
+
# This method also resets the states of other variables prior to creation.
|
162
|
+
# ==== Input
|
163
|
+
# [*args : Array] The parameters that will be used to create a new instance.
|
164
|
+
def create(*args)
|
165
|
+
reset_io
|
166
|
+
reset_trace
|
167
|
+
reset_app_state
|
168
|
+
@obj = init_new_object(*args)
|
155
169
|
end
|
156
170
|
|
157
|
-
#
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
scope = method_id.to_s.gsub(/_.*/, '')
|
171
|
+
# Creates a new object using the specified parameters.
|
172
|
+
# ==== Input
|
173
|
+
# [*args : Array] The parameters to send to the new method
|
174
|
+
# when creating the object.
|
175
|
+
def init_new_object(*args)
|
176
|
+
@obj = send_to_class(:new, *args)
|
177
|
+
end
|
166
178
|
|
167
|
-
|
168
|
-
|
179
|
+
# Sets the value of the variable that indicates whether a new object
|
180
|
+
# should be created and sets the parameters that will be used.
|
181
|
+
# ==== Output
|
182
|
+
# [params : Array] The parameters to use when creating the object.
|
183
|
+
# ==== Notes
|
184
|
+
# This method should only be called from a child class's initialize method.
|
185
|
+
# Calling it elsewhere could cause unexpected results.
|
186
|
+
def init_object(*params)
|
187
|
+
@init_object = true
|
188
|
+
|
189
|
+
case params.length
|
190
|
+
when 0
|
191
|
+
@init_object_params = nil
|
192
|
+
when 1
|
193
|
+
@init_object_params = params[0]
|
194
|
+
else
|
195
|
+
@init_object_params = *params
|
169
196
|
end
|
170
|
-
|
171
|
-
# If this is not at the end, the loop will attempt to do it's thing
|
172
|
-
# with the constructor created in this method, which is not necessary.
|
173
|
-
set_initializer
|
174
197
|
end
|
175
198
|
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
# Tracing data includes method name, parameters, and result.
|
180
|
-
# ==== Input
|
181
|
-
# [method_list : Array] A list of methods that will have wrapping functions
|
182
|
-
# created to enable tracing.
|
183
|
-
# [scope : String] The scope of the original function.
|
184
|
-
def set_instance_methods(method_list, scope)
|
185
|
-
method_list.each do |method_id|
|
186
|
-
# Setters and methods that accept blocks do not appear to work.
|
187
|
-
next if method_id =~ /=/ or method_id =~ /wrap_output/
|
188
|
-
|
189
|
-
# Build the method.
|
190
|
-
new_method = <<-DOC
|
191
|
-
alias :test_case_#{method_id} :#{method_id}
|
192
|
-
def #{method_id}(*args)
|
193
|
-
result = test_case_#{method_id}(*args)
|
194
|
-
@trace << {
|
195
|
-
:method => '#{method_id}',
|
196
|
-
:args => args,
|
197
|
-
:result => result
|
198
|
-
}
|
199
|
-
return result
|
200
|
-
end
|
201
|
-
#{scope} :#{method_id}
|
202
|
-
DOC
|
203
|
-
|
204
|
-
# Add the method to the class.
|
205
|
-
@class.class_eval do
|
206
|
-
eval(new_method)
|
207
|
-
end
|
208
|
-
end
|
199
|
+
# Initializes a new object using the default parameters.
|
200
|
+
def init_with_defaults
|
201
|
+
init_new_object(*@init_object_params)
|
209
202
|
end
|
210
203
|
|
211
|
-
#
|
212
|
-
# with the old method name followed by '_public_test'. If the original
|
213
|
-
# method contained a '?', it will be removed in the new method.
|
204
|
+
# Sends a call to the class.
|
214
205
|
# ==== Input
|
215
|
-
# [
|
216
|
-
#
|
217
|
-
|
218
|
-
|
219
|
-
def expose_private_methods(type, methods)
|
220
|
-
# Get the text that the method should be wrapped in.
|
221
|
-
method_wrapper = wrapper(type)
|
222
|
-
|
223
|
-
# Loop through the methods.
|
224
|
-
methods.each do |method|
|
225
|
-
# Remove ?s.
|
226
|
-
new_method = method.to_s.gsub(/\?/, '')
|
227
|
-
|
228
|
-
# This is the new method.
|
229
|
-
new_method = <<-DOC
|
230
|
-
def #{new_method}_public_test(*args)
|
231
|
-
#{method}(*args)
|
232
|
-
end
|
233
|
-
DOC
|
234
|
-
|
235
|
-
# Add the wrapping text.
|
236
|
-
new_method = method_wrapper % [new_method]
|
237
|
-
|
238
|
-
# Add the method to the class.
|
239
|
-
@class.class_eval do
|
240
|
-
eval(new_method)
|
241
|
-
end
|
242
|
-
end
|
206
|
+
# [method : Symbol, String] The method to call.
|
207
|
+
# [*args : Array] The parameters to send.
|
208
|
+
def send_to_class(method, *args)
|
209
|
+
return send_to(@class, method.to_sym, *args)
|
243
210
|
end
|
244
211
|
|
245
|
-
#
|
246
|
-
#
|
247
|
-
# New methods will be created (a getter and a setter) for each variable.
|
248
|
-
#
|
249
|
-
# Regardless of the type of variable, these methods are only available
|
250
|
-
# via an instance.
|
212
|
+
# Sends a method to the object in the class variable.
|
251
213
|
# ==== Input
|
252
|
-
# [
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
# Remove any @s.
|
260
|
-
new_method = var.to_s.gsub(/@/, '')
|
214
|
+
# [method : Symbol, String] The name of the method to call.
|
215
|
+
# [*args : Array] Parameters to use when calling the method.
|
216
|
+
def send_to_object(method, *args)
|
217
|
+
create(*args)
|
218
|
+
assert_alive
|
219
|
+
return send_to(@obj, method.to_sym, *args)
|
220
|
+
end
|
261
221
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
#{var}
|
266
|
-
end
|
222
|
+
############################################################################
|
223
|
+
# Enable Functionality - These should only be called in initialize of a child.
|
224
|
+
############################################################################
|
267
225
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
226
|
+
# Indicate that class and instance variables should be made available
|
227
|
+
# via public methods.
|
228
|
+
def expose_all_variables
|
229
|
+
@expose_variables = true
|
230
|
+
end
|
272
231
|
|
273
|
-
|
274
|
-
|
232
|
+
# Indicate that private class methods should be made available
|
233
|
+
# via public class methods.
|
234
|
+
def expose_class_methods
|
235
|
+
@expose_class_methods = true
|
236
|
+
end
|
275
237
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
end
|
238
|
+
# Indicate that private instance methods should be made available
|
239
|
+
# via public instance methods.
|
240
|
+
def expose_instance_methods
|
241
|
+
@expose_instance_methods = true
|
281
242
|
end
|
282
243
|
|
283
|
-
#
|
284
|
-
#
|
285
|
-
|
286
|
-
|
287
|
-
# Only :class & :instance are supported.
|
288
|
-
# ==== Output
|
289
|
-
# [String] The text that the specified type of method should be wrapped in.
|
290
|
-
def wrapper(type)
|
291
|
-
case type
|
292
|
-
when :class then 'class << self;%s;end'
|
293
|
-
when :instance then '%s'
|
294
|
-
end
|
244
|
+
# Enables stack tracing so that assertions which rely on knowing
|
245
|
+
# which methods were called may be used.
|
246
|
+
def expose_stack
|
247
|
+
@expose_stack = true
|
295
248
|
end
|
296
249
|
|
297
250
|
############################################################################
|
298
251
|
# I/O support methods.
|
299
252
|
############################################################################
|
300
253
|
|
254
|
+
# Returns the output from stdout as a string.
|
255
|
+
# ==== Output
|
256
|
+
# [String] The output from stdout.
|
257
|
+
#
|
258
|
+
# All trailing line feeds are removed.
|
259
|
+
def out
|
260
|
+
@out.respond_to?(:string) ? @out.string.gsub(/\n*\z/, '') : ''
|
261
|
+
end
|
262
|
+
|
263
|
+
# Returns the output from stderr as a string.
|
264
|
+
# ==== Output
|
265
|
+
# [String] The output from stderr.
|
266
|
+
#
|
267
|
+
# All trailing line feeds are removed.
|
268
|
+
def err
|
269
|
+
@err.respond_to?(:string) ? @err.string.gsub(/\n*\z/, '') : ''
|
270
|
+
end
|
271
|
+
|
301
272
|
# Return the actual output to stdout and stderr.
|
302
273
|
# ==== Output
|
303
274
|
# [Array] Two element array of strings.
|
@@ -309,6 +280,12 @@ Test::Unit::TestCase.class_eval do
|
|
309
280
|
return out, err
|
310
281
|
end
|
311
282
|
|
283
|
+
# Reset the stdout and stderr stream variables.
|
284
|
+
def reset_io
|
285
|
+
@out = StringIO.new
|
286
|
+
@err = StringIO.new
|
287
|
+
end
|
288
|
+
|
312
289
|
# Wrap a block to capture the output to stdout and stderr.
|
313
290
|
# ==== Input
|
314
291
|
# [&block : Block] The block of code that will have stdout and stderr trapped.
|
@@ -317,55 +294,21 @@ Test::Unit::TestCase.class_eval do
|
|
317
294
|
$stdout = @out
|
318
295
|
$stderr = @err
|
319
296
|
yield
|
297
|
+
rescue SystemExit
|
298
|
+
AppState.state = :dead
|
320
299
|
ensure
|
321
300
|
$stdout = STDOUT
|
322
301
|
$stderr = STDERR
|
323
302
|
end
|
324
303
|
end
|
325
304
|
|
326
|
-
# Returns the output from stdout as a string.
|
327
|
-
# ==== Output
|
328
|
-
# [String] The output from stdout.
|
329
|
-
#
|
330
|
-
# All trailing line feeds are removed.
|
331
|
-
def out
|
332
|
-
@out.respond_to?(:string) ? @out.string.gsub(/\n*\z/, '') : ''
|
333
|
-
end
|
334
|
-
|
335
|
-
# Returns the output from stderr as a string.
|
336
|
-
# ==== Output
|
337
|
-
# [String] The output from stderr.
|
338
|
-
#
|
339
|
-
# All trailing line feeds are removed.
|
340
|
-
def err
|
341
|
-
@err.respond_to?(:string) ? @err.string.gsub(/\n*\z/, '') : ''
|
342
|
-
end
|
343
|
-
|
344
|
-
# Reset the stdout and stderr stream variables.
|
345
|
-
def reset_io
|
346
|
-
@out = StringIO.new
|
347
|
-
@err = StringIO.new
|
348
|
-
end
|
349
|
-
|
350
305
|
############################################################################
|
351
306
|
# Support methods.
|
352
307
|
############################################################################
|
353
308
|
|
354
|
-
# Indicates whether the specified method has been called on a given class.
|
355
|
-
# ==== Input
|
356
|
-
# [method_name : String] The name of the method.
|
357
|
-
#
|
358
|
-
# This value may be a string or a symbol.
|
359
|
-
# [class_name : String : @class.name] The name of the class that the method
|
360
|
-
# should have been invoked from.
|
361
|
-
def method_called?(method_name, class_name = @class.name)
|
362
|
-
!@stack_trace.index(
|
363
|
-
{:method => method_name.to_sym, :class => class_name}).nil?
|
364
|
-
end
|
365
|
-
|
366
309
|
# Set the application state to alive.
|
367
310
|
def reset_app_state
|
368
|
-
|
311
|
+
AppState.state = :alive unless AppState.alive
|
369
312
|
end
|
370
313
|
|
371
314
|
# Resets the trace arrays.
|
@@ -387,14 +330,6 @@ Test::Unit::TestCase.class_eval do
|
|
387
330
|
# Assertions.
|
388
331
|
############################################################################
|
389
332
|
|
390
|
-
# Asserts that a value is equal to false.
|
391
|
-
# ==== Input
|
392
|
-
# [value : Any] The value to check for equality against false.
|
393
|
-
# [message : String : nil] The message to display if the value is not false.
|
394
|
-
def assert_false(value, message = nil)
|
395
|
-
assert_equal false, value, message
|
396
|
-
end
|
397
|
-
|
398
333
|
# Asserts that a value is equal to true.
|
399
334
|
# ==== Input
|
400
335
|
# [value : Any] The value to check for equality against true.
|
@@ -403,6 +338,14 @@ Test::Unit::TestCase.class_eval do
|
|
403
338
|
assert_equal true, value, message
|
404
339
|
end
|
405
340
|
|
341
|
+
# Asserts that a value is equal to false.
|
342
|
+
# ==== Input
|
343
|
+
# [value : Any] The value to check for equality against false.
|
344
|
+
# [message : String : nil] The message to display if the value is not false.
|
345
|
+
def assert_false(value, message = nil)
|
346
|
+
assert_equal false, value, message
|
347
|
+
end
|
348
|
+
|
406
349
|
# Asserts that the negation of a value is true.
|
407
350
|
# ==== Input
|
408
351
|
# [value : Any] The value which will be negated and then asserted.
|
@@ -513,39 +456,250 @@ Test::Unit::TestCase.class_eval do
|
|
513
456
|
# Assertions - Application state.
|
514
457
|
############################################################################
|
515
458
|
|
516
|
-
# Asserts that the application
|
459
|
+
# Asserts that the application is still running.
|
517
460
|
# ==== Input
|
518
461
|
# [message : String : nil] The message to show if the assertion fails.
|
519
|
-
def
|
520
|
-
message = "#{@class}
|
462
|
+
def assert_alive(message = nil)
|
463
|
+
message = "#{@class} is not running as expected" if message.nil?
|
521
464
|
|
522
465
|
# Hold the state in a local variable so that the state can be reset
|
523
466
|
# prior to the assertion.
|
524
|
-
|
467
|
+
alive = AppState.alive
|
525
468
|
|
526
469
|
# Reset the application state so that later tests are not adversely
|
527
470
|
# affected if this assertion fails, which otherwise could leave
|
528
471
|
# the application in an incorrect state.
|
529
472
|
reset_app_state
|
530
473
|
|
531
|
-
|
474
|
+
assert alive, message
|
532
475
|
end
|
533
476
|
|
534
|
-
# Asserts that the application
|
477
|
+
# Asserts that the application has been stopped.
|
535
478
|
# ==== Input
|
536
479
|
# [message : String : nil] The message to show if the assertion fails.
|
537
|
-
def
|
538
|
-
message = "#{@class}
|
480
|
+
def assert_dead(message = nil)
|
481
|
+
message = "#{@class} was not stopped as expected" if message.nil?
|
539
482
|
|
540
483
|
# Hold the state in a local variable so that the state can be reset
|
541
484
|
# prior to the assertion.
|
542
|
-
|
485
|
+
dead = AppState.dead
|
543
486
|
|
544
487
|
# Reset the application state so that later tests are not adversely
|
545
488
|
# affected if this assertion fails, which otherwise could leave
|
546
489
|
# the application in an incorrect state.
|
547
490
|
reset_app_state
|
548
491
|
|
549
|
-
|
492
|
+
assert dead, message
|
493
|
+
end
|
494
|
+
|
495
|
+
############################################################################
|
496
|
+
private
|
497
|
+
############################################################################
|
498
|
+
|
499
|
+
# Private methods are intended for use in this class only.
|
500
|
+
# They are NOT intended for use in sub-classes.
|
501
|
+
|
502
|
+
############################################################################
|
503
|
+
# @obj and @class-related methods
|
504
|
+
############################################################################
|
505
|
+
|
506
|
+
# Indicates whether a new object instance should (and can)
|
507
|
+
# be created during initialization.
|
508
|
+
# ==== Output
|
509
|
+
# [Boolean] Whether a new object should (and can) be created.
|
510
|
+
def new_object_on_init?
|
511
|
+
@init_object && @class.respond_to?(:new)
|
512
|
+
end
|
513
|
+
|
514
|
+
# Sends a method to the specified object along with parameters.
|
515
|
+
# ==== Input
|
516
|
+
# [object : Any] The object to send the method to.
|
517
|
+
# [method : Symbol, String] The method to call.
|
518
|
+
# [*args : Array] The parameters to pass to the method.
|
519
|
+
def send_to(object, method, *args)
|
520
|
+
result = nil
|
521
|
+
|
522
|
+
if args.length == 0
|
523
|
+
wrap_output { result = object.send(method.to_sym) }
|
524
|
+
else
|
525
|
+
wrap_output { result = object.send(method.to_sym, *args) }
|
526
|
+
end
|
527
|
+
|
528
|
+
return result
|
529
|
+
end
|
530
|
+
|
531
|
+
############################################################################
|
532
|
+
# Monkey patching methods for the class being tested.
|
533
|
+
############################################################################
|
534
|
+
|
535
|
+
# Monkey patch the class's initializer to enable tracing
|
536
|
+
# with parameters and results.
|
537
|
+
def set_initializer
|
538
|
+
@class.class_eval do
|
539
|
+
attr_accessor :trace
|
540
|
+
|
541
|
+
alias :test_case_initialize :initialize
|
542
|
+
def initialize(*args)
|
543
|
+
@trace = []
|
544
|
+
result = test_case_initialize(*args)
|
545
|
+
return result
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
# Loop through the instance methods, calling set_instance_methods for each.
|
551
|
+
def set_instance_method_wrappers
|
552
|
+
[
|
553
|
+
:public_instance_methods,
|
554
|
+
:protected_instance_methods,
|
555
|
+
:private_instance_methods,
|
556
|
+
].each do |method_id|
|
557
|
+
|
558
|
+
scope = method_id.to_s.gsub(/_.*/, '')
|
559
|
+
|
560
|
+
set_instance_methods(@class.send(method_id) -
|
561
|
+
@class.superclass.send(method_id), scope)
|
562
|
+
end
|
563
|
+
|
564
|
+
# If this is not at the end, the loop will attempt to do it's thing
|
565
|
+
# with the constructor created in this method, which is not necessary.
|
566
|
+
set_initializer
|
567
|
+
end
|
568
|
+
|
569
|
+
# Loop through the list of methods that are passed in,
|
570
|
+
# creating a wrapper method that enables tracing.
|
571
|
+
#
|
572
|
+
# Tracing data includes method name, parameters, and result.
|
573
|
+
# ==== Input
|
574
|
+
# [method_list : Array] A list of methods that will have wrapping functions
|
575
|
+
# created to enable tracing.
|
576
|
+
# [scope : String] The scope of the original function.
|
577
|
+
def set_instance_methods(method_list, scope)
|
578
|
+
method_list.each do |method_id|
|
579
|
+
# Setters and methods that accept blocks do not appear to work.
|
580
|
+
next if method_id =~ /=/ or method_id =~ /wrap_output/
|
581
|
+
|
582
|
+
# Build the method.
|
583
|
+
new_method = <<-DOC
|
584
|
+
alias :test_case_#{method_id} :#{method_id}
|
585
|
+
def #{method_id}(*args)
|
586
|
+
result = test_case_#{method_id}(*args)
|
587
|
+
@trace << {
|
588
|
+
:method => '#{method_id}',
|
589
|
+
:args => args,
|
590
|
+
:result => result
|
591
|
+
}
|
592
|
+
return result
|
593
|
+
end
|
594
|
+
#{scope} :#{method_id}
|
595
|
+
DOC
|
596
|
+
|
597
|
+
# Add the method to the class.
|
598
|
+
@class.class_eval do
|
599
|
+
eval(new_method)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
# Expose the private methods that are passed in. New methods will be created
|
605
|
+
# with the old method name followed by '_public_test'. If the original
|
606
|
+
# method contained a '?', it will be removed in the new method.
|
607
|
+
# ==== Input
|
608
|
+
# [type : Symbol] Indicates whether to handle instance or class methods.
|
609
|
+
#
|
610
|
+
# Only :class and :instance are supported.
|
611
|
+
# [methods : Array] An array of the methods to expose.
|
612
|
+
def expose_private_methods(type, methods)
|
613
|
+
# Get the text that the method should be wrapped in.
|
614
|
+
method_wrapper = wrapper(type)
|
615
|
+
|
616
|
+
# Loop through the methods.
|
617
|
+
methods.each do |method|
|
618
|
+
# Remove ?s.
|
619
|
+
new_method = method.to_s.gsub(/\?/, '')
|
620
|
+
|
621
|
+
# This is the new method.
|
622
|
+
new_method = <<-DOC
|
623
|
+
def #{new_method}_public_test(*args)
|
624
|
+
#{method}(*args)
|
625
|
+
end
|
626
|
+
DOC
|
627
|
+
|
628
|
+
# Add the wrapping text.
|
629
|
+
new_method = method_wrapper % [new_method]
|
630
|
+
|
631
|
+
# Add the method to the class.
|
632
|
+
@class.class_eval do
|
633
|
+
eval(new_method)
|
634
|
+
end
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
# Expose the variables.
|
639
|
+
#
|
640
|
+
# New methods will be created (a getter and a setter) for each variable.
|
641
|
+
#
|
642
|
+
# Regardless of the type of variable, these methods are only available
|
643
|
+
# via an instance.
|
644
|
+
# ==== Input
|
645
|
+
# [variables : Array] An array of variables to expose.
|
646
|
+
def expose_variables(variables)
|
647
|
+
# Get the text that the methods should be wrapped in.
|
648
|
+
var_wrapper = wrapper(:instance)
|
649
|
+
|
650
|
+
# Loop through the variables
|
651
|
+
variables.each do |var|
|
652
|
+
# Remove any @s.
|
653
|
+
new_method = var.to_s.gsub(/@/, '')
|
654
|
+
|
655
|
+
# These are the new getter and setters.
|
656
|
+
new_method = <<-DOC
|
657
|
+
def #{new_method}_variable_method
|
658
|
+
#{var}
|
659
|
+
end
|
660
|
+
|
661
|
+
def #{new_method}_variable_method=(value)
|
662
|
+
#{var} = value
|
663
|
+
end
|
664
|
+
DOC
|
665
|
+
|
666
|
+
# Add the wrapping text.
|
667
|
+
new_method = var_wrapper % [new_method]
|
668
|
+
|
669
|
+
# Add the methods to the class.
|
670
|
+
@class.class_eval do
|
671
|
+
eval(new_method)
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
# Returns the wrapping text for the specified type of method.
|
677
|
+
# ==== Input
|
678
|
+
# [type : Symbol] Indicates whether to handle instance or class methods.
|
679
|
+
#
|
680
|
+
# Only :class & :instance are supported.
|
681
|
+
# ==== Output
|
682
|
+
# [String] The text that the specified type of method should be wrapped in.
|
683
|
+
def wrapper(type)
|
684
|
+
case type
|
685
|
+
when :class then 'class << self;%s;end'
|
686
|
+
when :instance then '%s'
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
############################################################################
|
691
|
+
# Support methods.
|
692
|
+
############################################################################
|
693
|
+
|
694
|
+
# Indicates whether the specified method has been called on a given class.
|
695
|
+
# ==== Input
|
696
|
+
# [method_name : String] The name of the method.
|
697
|
+
#
|
698
|
+
# This value may be a string or a symbol.
|
699
|
+
# [class_name : String : @class.name] The name of the class that the method
|
700
|
+
# should have been invoked from.
|
701
|
+
def method_called?(method_name, class_name = @class.name)
|
702
|
+
!@stack_trace.index(
|
703
|
+
{:method => method_name.to_sym, :class => class_name}).nil?
|
550
704
|
end
|
551
705
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
# This file contains the
|
2
|
-
# application is still running or not.
|
1
|
+
# This file contains the main part of the module for this gem.
|
3
2
|
|
4
3
|
#--
|
5
4
|
################################################################################
|
@@ -33,7 +32,8 @@
|
|
33
32
|
################################################################################
|
34
33
|
#++
|
35
34
|
|
35
|
+
# Main module for this gem.
|
36
36
|
module TestInternals
|
37
|
-
# This constant is used to
|
38
|
-
AppState =
|
37
|
+
# This constant is used to indicate whether the application has been stopped.
|
38
|
+
AppState = StateManager.new(:alive, [:alive, :dead])
|
39
39
|
end
|
data/lib/test_internals.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
gem_name = File.basename(__FILE__, '.rb')
|
2
2
|
|
3
|
-
require 'app_mode'
|
4
3
|
require 'test/unit'
|
4
|
+
require 'app_mode'
|
5
5
|
|
6
|
-
require_relative File.join(gem_name,
|
7
|
-
require_relative File.join(gem_name, 'kernel')
|
6
|
+
require_relative File.join(gem_name, gem_name)
|
8
7
|
require_relative File.join(gem_name, 'test_case')
|
data/test_internals.gemspec
CHANGED
@@ -1,19 +1,22 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'test_internals'
|
3
|
-
s.version = '0.0
|
3
|
+
s.version = '1.0.0'
|
4
4
|
|
5
5
|
s.summary = 'Allows tests to check the stack trace, ' +
|
6
6
|
'parameters, private methods, and class variables.'
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
|
8
|
+
s.description = %Q{
|
9
|
+
TestInternals patches Test::Unit::TestCase to allow
|
10
|
+
testing of private methods, as well as variables. The stack trace
|
11
|
+
is also available, including the ability to check that specific
|
12
|
+
parameters were sent to a method. This results in cotton candy goodness for all.
|
13
|
+
}.strip
|
11
14
|
|
12
15
|
s.author = 'Travis Herrick'
|
13
16
|
s.email = 'tthetoad@gmail.com'
|
14
17
|
s.homepage = 'http://www.bitbucket.org/ToadJamb/gems_test_internals'
|
15
18
|
|
16
|
-
s.license = '
|
19
|
+
s.license = 'GPLv3'
|
17
20
|
|
18
21
|
s.extra_rdoc_files << 'README'
|
19
22
|
|
@@ -21,7 +24,7 @@ Gem::Specification.new do |s|
|
|
21
24
|
s.files = Dir['lib/**/*.rb', '*']
|
22
25
|
s.test_files = Dir['test/**/*.rb']
|
23
26
|
|
24
|
-
s.add_dependency 'app_mode', '~> 0.0
|
27
|
+
s.add_dependency 'app_mode', '~> 1.0.0'
|
25
28
|
|
26
29
|
s.add_development_dependency 'rake_tasks', '~> 0.0.1'
|
27
30
|
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: test_internals
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
+
- 1
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 0.0.2
|
9
|
+
version: 1.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Travis Herrick
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-08-
|
17
|
+
date: 2011-08-15 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -25,10 +25,10 @@ dependencies:
|
|
25
25
|
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
segments:
|
28
|
+
- 1
|
28
29
|
- 0
|
29
30
|
- 0
|
30
|
-
|
31
|
-
version: 0.0.1
|
31
|
+
version: 1.0.0
|
32
32
|
type: :runtime
|
33
33
|
prerelease: false
|
34
34
|
version_requirements: *id001
|
@@ -47,7 +47,11 @@ dependencies:
|
|
47
47
|
type: :development
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: *id002
|
50
|
-
description:
|
50
|
+
description: |-
|
51
|
+
TestInternals patches Test::Unit::TestCase to allow
|
52
|
+
testing of private methods, as well as variables. The stack trace
|
53
|
+
is also available, including the ability to check that specific
|
54
|
+
parameters were sent to a method. This results in cotton candy goodness for all.
|
51
55
|
email: tthetoad@gmail.com
|
52
56
|
executables: []
|
53
57
|
|
@@ -56,19 +60,18 @@ extensions: []
|
|
56
60
|
extra_rdoc_files:
|
57
61
|
- README
|
58
62
|
files:
|
59
|
-
- lib/test_internals/test_case.rb
|
60
|
-
- lib/test_internals/app_state.rb
|
61
|
-
- lib/test_internals/kernel.rb
|
62
63
|
- lib/test_internals.rb
|
64
|
+
- lib/test_internals/test_case.rb
|
65
|
+
- lib/test_internals/test_internals.rb
|
63
66
|
- Gemfile.lock
|
64
67
|
- Gemfile
|
65
|
-
- rakefile
|
66
68
|
- README
|
69
|
+
- rakefile
|
67
70
|
- test_internals.gemspec
|
68
71
|
has_rdoc: true
|
69
72
|
homepage: http://www.bitbucket.org/ToadJamb/gems_test_internals
|
70
73
|
licenses:
|
71
|
-
-
|
74
|
+
- GPLv3
|
72
75
|
post_install_message:
|
73
76
|
rdoc_options: []
|
74
77
|
|
@@ -79,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
82
|
requirements:
|
80
83
|
- - ">="
|
81
84
|
- !ruby/object:Gem::Version
|
82
|
-
hash:
|
85
|
+
hash: 2800249786482312969
|
83
86
|
segments:
|
84
87
|
- 0
|
85
88
|
version: "0"
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# This file contains a monkey patch of Kernel functions for use during testing.
|
2
|
-
|
3
|
-
#--
|
4
|
-
################################################################################
|
5
|
-
# Copyright (C) 2011 Travis Herrick #
|
6
|
-
################################################################################
|
7
|
-
# #
|
8
|
-
# \v^V,^!v\^/ #
|
9
|
-
# ~% %~ #
|
10
|
-
# { _ _ } #
|
11
|
-
# ( * - ) #
|
12
|
-
# | / | #
|
13
|
-
# \ _, / #
|
14
|
-
# \__.__/ #
|
15
|
-
# #
|
16
|
-
################################################################################
|
17
|
-
# This program is free software: you can redistribute it #
|
18
|
-
# and/or modify it under the terms of the GNU General Public License #
|
19
|
-
# as published by the Free Software Foundation, #
|
20
|
-
# either version 3 of the License, or (at your option) any later version. #
|
21
|
-
# #
|
22
|
-
# Commercial licensing may be available for a fee under a different license. #
|
23
|
-
################################################################################
|
24
|
-
# This program is distributed in the hope that it will be useful, #
|
25
|
-
# but WITHOUT ANY WARRANTY; #
|
26
|
-
# without even the implied warranty of MERCHANTABILITY #
|
27
|
-
# or FITNESS FOR A PARTICULAR PURPOSE. #
|
28
|
-
# See the GNU General Public License for more details. #
|
29
|
-
# #
|
30
|
-
# You should have received a copy of the GNU General Public License #
|
31
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
32
|
-
################################################################################
|
33
|
-
#++
|
34
|
-
|
35
|
-
# Monkey patch Kernel classes and functions for testing.
|
36
|
-
module Kernel
|
37
|
-
# Patch exit so that it sets a flag rather than ends the application.
|
38
|
-
# (A call to exit will cause testing to stop otherwise).
|
39
|
-
def exit(*args)
|
40
|
-
TestInternals::AppState.state = :dead
|
41
|
-
end
|
42
|
-
end
|