class Object
Public Class Methods
Initializes the class and exposes private methods and variables of the class that is being tested.
# File lib/test_internals/test_case.rb, line 50 def initialize(*args) # Call initialize on the superclass. super @obj = nil @class = nil unless defined?(@class) @init_object = nil unless defined?(@init_object) @init_object_params = nil unless defined?(@init_object_params) @expose_instance_methods = nil unless defined?(@expose_instance_methods) @expose_class_methods = nil unless defined?(@expose_class_methods) @expose_variables = nil unless defined?(@expose_variables) @expose_stack = nil unless defined?(@expose_stack) reset_io # This block ensures that tests still work if there is not a class that # corresponds with the test file/class. begin # Get the class that is being tested. # Assume that the name of the class is found by removing 'Test' # from the test class. @class ||= Kernel.const_get(self.class.name.gsub(/Test$/, '')) @@initialized = ((@class.name == @@class_name) && @@initialized) @@class_name = @class.name rescue @@initialized = true @@class_name = '' end # Only patch if this code has not yet been run. if !@@initialized set_instance_method_wrappers if @expose_stack # Expose private class methods. # We will only expose the methods we are responsible for creating. # (i.e. subtracting the superclass's private methods) expose_private_methods(:class, @class.private_methods - @class.superclass.private_methods) if @expose_class_methods # Expose private instance methods. # We will only expose the methods we are responsible for creating. # (i.e. subtracting the superclass's private methods) expose_private_methods(:instance, @class.private_instance_methods - @class.superclass.private_instance_methods) if @expose_instance_methods # Expose variables. # Requires that variables are assigned to in the constructor. if @expose_variables init_with_defaults if new_object_on_init? instance_variable_list = @obj.nil? ? [] : @obj.instance_variables expose_variables @class.class_variables + instance_variable_list end # Indicate that this code has been run. @@initialized = true end # This is potentially called a second time so that the object will # include any goodies we have added here. init_with_defaults if new_object_on_init? reset_trace # If initializing the class with @class.new above kills the app, # we need to set it back to running, but we want to do this regardless. reset_app_state end
Public Instance Methods
Asserts that the application is still running.
Input¶ ↑
- message : String : nil
-
The message to show if the assertion fails.
# File lib/test_internals/test_case.rb, line 460 def assert_alive(message = nil) message = "#{@class} is not running as expected" if message.nil? # Hold the state in a local variable so that the state can be reset # prior to the assertion. alive = TestInternals::AppState.alive # Reset the application state so that later tests are not adversely # affected if this assertion fails, which otherwise could leave # the application in an incorrect state. reset_app_state assert alive, message end
Assert that an array has a specified number of elements.
Input¶ ↑
- array : Array
-
The array that will have it's length checked.
- length : Fixnum
-
The length that the array should be.
- message : String : nil
-
The message to display if the assertion fails.
# File lib/test_internals/test_case.rb, line 360 def assert_array_count(array, length, message = nil) if message.nil? message = "#{array} has #{array.length} item(s), " + "but was expected to have #{length}." end assert array.length == length, message end
Asserts that the application has been stopped.
Input¶ ↑
- message : String : nil
-
The message to show if the assertion fails.
# File lib/test_internals/test_case.rb, line 478 def assert_dead(message = nil) message = "#{@class} was not stopped as expected" if message.nil? # Hold the state in a local variable so that the state can be reset # prior to the assertion. dead = TestInternals::AppState.dead # Reset the application state so that later tests are not adversely # affected if this assertion fails, which otherwise could leave # the application in an incorrect state. reset_app_state assert dead, message end
Asserts that a value is equal to false.
Input¶ ↑
- value : Any
-
The value to check for equality against false.
- message : String : nil
-
The message to display if the value is not false.
# File lib/test_internals/test_case.rb, line 343 def assert_false(value, message = nil) assert_equal false, value, message end
Asserts that a method was called on a class.
Input¶ ↑
- method_name : String
-
The name of the method to check for.
- class_name : String : @class.name
-
The name of the class on which
method_name
should have been invoked.
# File lib/test_internals/test_case.rb, line 379 def assert_method(method_name, class_name = @class.name) assert method_called?(method_name.to_sym, class_name), "#{class_name}.#{method_name} has not been called." end
Asserts that the negation of a value is true.
Input¶ ↑
- value : Any
-
The value which will be negated and then asserted.
- message : String : nil
-
The message to display if the assertion fails.
# File lib/test_internals/test_case.rb, line 351 def assert_not(value, message = nil) assert !value, message end
Asserts that a method was not called on a class.
Input¶ ↑
- method_name : String
-
The name of the method to check for.
- class_name : String : @class.name
-
The name of the class on which
method_name
should not have been invoked.
# File lib/test_internals/test_case.rb, line 390 def assert_not_method(method_name, class_name = @class.name) assert !method_called?(method_name.to_sym, class_name), "#{class_name}.#{method_name} should not be called." end
Asserts that a method was called with the specified parameters.
Input¶ ↑
- method_name : String
-
The name of the method to check.
- *args : Array
-
The parameters that were passed in to the method.
# File lib/test_internals/test_case.rb, line 399 def assert_trace_args(method_name, *args) match = false list = [] # Loop through the stack trace to see if the method was called # with the specified arguments. @obj.trace.each do |trace| if trace[:method] == method_name and trace[:args] == args match = true break elsif trace[:method] == method_name list << trace[:args] end end assert match, "#{method_name} was not called with the following parameters:\n" + "#{args.join("\n" + '-' * 80 + "\n")}\n" + '*' * 80 + "\n" + "#{method_name} was recorded as follows:\n" + "#{list.join("\n" + '-' * 80 + "\n")}" end
Asserts that a method was called with the specified parameters and returned the specified result.
Input¶ ↑
- method_name : String
-
The name of the method to check.
- result : Any
-
The expected result of the method call.
- *args : Array
-
The parameters that were passed in to the method.
# File lib/test_internals/test_case.rb, line 429 def assert_trace_info(method_name, result, *args) match = (@obj.trace.index( {:methd => method_name, :args => args, :result => result})) list = [] # Only get a list of possible results if a match was not found. unless match @obj.trace.each do |trace| if trace[:method] == method_name list << {:args => trace[:args], :result => trace[:result]} end end end assert match, "#{method_name} was not called with the following parameters:\n" + "#{args}\n" + "or did not return the following result:\n" + "#{result}\n" + "#{method_name} was recorded as follows:\n" + "#{list.join("\n" + '-' * 80 + "\n")}" end
Asserts that a value is equal to true.
Input¶ ↑
- value : Any
-
The value to check for equality against true.
- message : String : nil
-
The message to display if the value is not true.
# File lib/test_internals/test_case.rb, line 335 def assert_true(value, message = nil) assert_equal true, value, message end
Creates a new instance of the class using the arguments that are passed in.
This method also resets the states of other variables prior to creation.
Input¶ ↑
- *args : Array
-
The parameters that will be used to create a new instance.
# File lib/test_internals/test_case.rb, line 162 def create(*args) reset_io reset_trace reset_app_state @obj = init_new_object(*args) end
Indicate that class and instance variables should be made available via public methods.
# File lib/test_internals/test_case.rb, line 226 def expose_all_variables @expose_variables = true end
Indicate that private class methods should be made available via public class methods.
# File lib/test_internals/test_case.rb, line 232 def expose_class_methods @expose_class_methods = true end
Indicate that private instance methods should be made available via public instance methods.
# File lib/test_internals/test_case.rb, line 238 def expose_instance_methods @expose_instance_methods = true end
Expose the private methods that are passed in. New methods will be created with the old method name followed by '_public_test'. If the original method contained a '?', it will be removed in the new method.
Input¶ ↑
- type : Symbol
-
Indicates whether to handle instance or class methods.
Only :class and :instance are supported.
- methods : Array
-
An array of the methods to expose.
# File lib/test_internals/test_case.rb, line 610 def expose_private_methods(type, methods) # Get the text that the method should be wrapped in. method_wrapper = wrapper(type) # Loop through the methods. methods.each do |method| # Remove ?s. new_method = method.to_s.gsub(/\?/, '') # This is the new method. new_method = <<-DOC def #{new_method}_public_test(*args) #{method}(*args) end DOC # Add the wrapping text. new_method = method_wrapper % [new_method] # Add the method to the class. @class.class_eval do eval(new_method) end end end
Enables stack tracing so that assertions which rely on knowing which methods were called may be used.
# File lib/test_internals/test_case.rb, line 244 def expose_stack @expose_stack = true end
Expose the variables.
New methods will be created (a getter and a setter) for each variable.
Regardless of the type of variable, these methods are only available via an instance.
Input¶ ↑
- variables : Array
-
An array of variables to expose.
# File lib/test_internals/test_case.rb, line 644 def expose_variables(variables) # Get the text that the methods should be wrapped in. var_wrapper = wrapper(:instance) # Loop through the variables variables.each do |var| # Remove any @s. new_method = var.to_s.gsub(/@/, '') # These are the new getter and setters. new_method = <<-DOC def #{new_method}_variable_method #{var} end def #{new_method}_variable_method=(value) #{var} = value end DOC # Add the wrapping text. new_method = var_wrapper % [new_method] # Add the methods to the class. @class.class_eval do eval(new_method) end end end
Sets the value of the variable that indicates whether a new object should be created and sets the parameters that will be used.
Output¶ ↑
- params : Array
-
The parameters to use when creating the object.
Notes¶ ↑
This method should only be called from a child class's initialize method. Calling it elsewhere could cause unexpected results.
# File lib/test_internals/test_case.rb, line 184 def init_object(*params) @init_object = true case params.length when 0 @init_object_params = nil when 1 @init_object_params = params[0] else @init_object_params = *params end end
Initializes a new object using the default parameters.
# File lib/test_internals/test_case.rb, line 198 def init_with_defaults init_new_object(*@init_object_params) end
Indicates whether the specified method has been called on a given class.
Input¶ ↑
- method_name : String
-
The name of the method.
This value may be a string or a symbol.
- class_name : String : @class.name
-
The name of the class that the method should have been invoked from.
# File lib/test_internals/test_case.rb, line 699 def method_called?(method_name, class_name = @class.name) !@stack_trace.index( {:method => method_name.to_sym, :class => class_name}).nil? end
Set the application state to alive.
# File lib/test_internals/test_case.rb, line 308 def reset_app_state TestInternals::AppState.state = :alive unless TestInternals::AppState.alive end
Reset the stdout and stderr stream variables.
# File lib/test_internals/test_case.rb, line 282 def reset_io @out = StringIO.new @err = StringIO.new end
Resets the trace arrays.
This is intended for use in cases where code may be called multiple times in a single test.
# File lib/test_internals/test_case.rb, line 316 def reset_trace @stack_trace = [] @obj.trace = [] if @obj.respond_to?(:trace=) end
Sends a method to the specified object along with parameters.
Input¶ ↑
- object : Any
-
The object to send the method to.
- method : Symbol, String
-
The method to call.
- *args : Array
-
The parameters to pass to the method.
# File lib/test_internals/test_case.rb, line 517 def send_to(object, method, *args) result = nil if args.length == 0 wrap_output { result = object.send(method.to_sym) } else wrap_output { result = object.send(method.to_sym, *args) } end return result end
Sends a method to the object in the class variable.
Input¶ ↑
- method : Symbol, String
-
The name of the method to call.
- *args : Array
-
Parameters to use when calling the method.
# File lib/test_internals/test_case.rb, line 214 def send_to_object(method, *args) create(*args) assert_alive return send_to(@obj, method.to_sym) end
Monkey patch the class's initializer to enable tracing with parameters and results.
# File lib/test_internals/test_case.rb, line 535 def set_initializer @class.class_eval do attr_accessor :trace alias :test_case_initialize :initialize def initialize(*args) @trace = [] result = test_case_initialize(*args) return result end end end
Loop through the instance methods, calling set_instance_methods
for each.
# File lib/test_internals/test_case.rb, line 549 def set_instance_method_wrappers [ :public_instance_methods, :protected_instance_methods, :private_instance_methods, ].each do |method_id| scope = method_id.to_s.gsub(/_.*/, '') set_instance_methods(@class.send(method_id) - @class.superclass.send(method_id), scope) end # If this is not at the end, the loop will attempt to do it's thing # with the constructor created in this method, which is not necessary. set_initializer end
Loop through the list of methods that are passed in, creating a wrapper method that enables tracing.
Tracing data includes method name, parameters, and result.
Input¶ ↑
- method_list : Array
-
A list of methods that will have wrapping functions created to enable tracing.
- scope : String
-
The scope of the original function.
# File lib/test_internals/test_case.rb, line 575 def set_instance_methods(method_list, scope) method_list.each do |method_id| # Setters and methods that accept blocks do not appear to work. next if method_id =~ /=/ or method_id =~ /wrap_output/ # Build the method. new_method = <<-DOC alias :test_case_#{method_id} :#{method_id} def #{method_id}(*args) result = test_case_#{method_id}(*args) @trace << { :method => '#{method_id}', :args => args, :result => result } return result end #{scope} :#{method_id} DOC # Add the method to the class. @class.class_eval do eval(new_method) end end end
Sets up functionality for all tests.
Tracing is set up here so that it is only running during tests.
If you want to disable tracing, simply override the setup method without calling super.
# File lib/test_internals/test_case.rb, line 128 def setup if @expose_stack set_trace_func proc { |event, file, line, id, binding, class_name| if class_name == @class and @stack_trace.last != {:class => class_name.name, :method => id} @stack_trace << { :class => class_name.name, :method => id, } end } end end
Shows the trace history as it stands, if the object supports it.
# File lib/test_internals/test_case.rb, line 322 def show_trace return unless defined? @obj puts @obj.trace.join("\n" + '-' * 80 + "\n") if @obj.respond_to?(:trace) end
Clean up after each test.
# File lib/test_internals/test_case.rb, line 143 def teardown set_trace_func nil if @expose_stack end
Wrap a block to capture the output to stdout and stderr.
Input¶ ↑
- &block : Block
-
The block of code that will have stdout and stderr trapped.
# File lib/test_internals/test_case.rb, line 290 def wrap_output(&block) begin $stdout = @out $stderr = @err yield rescue SystemExit TestInternals::AppState.state = :dead ensure $stdout = STDOUT $stderr = STDERR end end
Returns the wrapping text for the specified type of method.
Input¶ ↑
- type : Symbol
-
Indicates whether to handle instance or class methods.
Only :class & :instance are supported.
Output¶ ↑
- String
-
The text that the specified type of method should be wrapped in.
# File lib/test_internals/test_case.rb, line 681 def wrapper(type) case type when :class then 'class << self;%s;end' when :instance then '%s' end end