123456789_123456789_123456789_123456789_123456789_

Class: Test::Unit::TestCase

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: lib/test/unit/testcase.rb

Overview

Ties everything together. If you subclass and add your own test methods, it takes care of making them into tests and wrapping those tests into a suite. It also does the nitty-gritty of actually running an individual test and collecting its results into a TestResult object.

You can run two hooks before/after a TestCase run.

Example:

class TestMyClass < Test::Unit::TestCase
  class << self
    def startup
      #...
    end

    def shutdown
      #...
    end
  end

  def setup
    #...
  end

  def cleanup
    #...
  end

  def teardown
    #...
  end

  def test_my_method1
    #...
  end

  def test_my_method2
    #...
  end
end

Here is a call order:

  1. startup

  2. setup

  3. test_my_method1

  4. cleanup

  5. teardown

  6. setup

  7. test_my_method2

  8. cleanup

  9. teardown

  10. shutdown

You can set an attribute to each test.

Example:

class TestMyClass < Test::Unit::TestCase
  attribute :speed, :fast
  def test_my_fast_method
    # You can get the attribute via `self[]`
    self[:speed] # => :fast
    #...
  end

  attribute :speed, :slow
  def test_my_slow_method
    self[:speed] # => :slow
    #...
  end
end

Constant Summary

ErrorHandler - Included

NOT_PASS_THROUGH_EXCEPTIONS, NOT_PASS_THROUGH_EXCEPTION_NAMES, PASS_THROUGH_EXCEPTIONS, PASS_THROUGH_EXCEPTION_NAMES

Assertions - Included

NOT_SPECIFIED

Util::BacktraceFilter - Included

POWERASSERT_PREFIX, TESTUNIT_FILE_SEPARATORS, TESTUNIT_PREFIX, TESTUNIT_RB_FILE

Class Attribute Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Util::Output - Included

#capture_output

Returns output for standard output and standard error as string.

Util::BacktraceFilter - Included

Assertions - Included

#add_assertion

Called whenever an assertion is made.

#assert,
#assert_alias_method

Passes if object#alias_name is an alias method of object#original_name.

#assert_block

The assertion upon which all other assertions are based.

#assert_boolean

Passes if actual is a boolean value.

#assert_compare

Passes if expression “expected operator actual” is true.

#assert_const_defined

Passes if object.const_defined?(constant_name).

#assert_empty

Passes if object is empty.

#assert_equal

Passes if expected == actual.

#assert_fail_assertion

Passes if assertion is failed in block.

#assert_false

Passes if actual is false.

#assert_in_delta

Passes if expected_float and actual_float are equal within delta tolerance.

#assert_in_epsilon

Passes if expected_float and actual_float are equal within epsilon relative error of expected_float.

#assert_include

Passes if collection includes object.

#assert_includes
#assert_instance_of

Passes if object.instance_of?(klass).

#assert_kind_of

Passes if object.kind_of?(klass).

#assert_match

Passes if pattern =~ string.

#assert_nil

Passes if object is nil.

#assert_no_match

Deprecated.

#assert_not_const_defined

Passes if !object.const_defined?(constant_name).

#assert_not_empty

Passes if object is not empty.

#assert_not_equal

Passes if expected != actual

#assert_not_in_delta

Passes if expected_float and actual_float are not equal within delta tolerance.

#assert_not_in_epsilon

Passes if expected_float and actual_float are not equal within epsilon relative error of expected_float.

#assert_not_include

Passes if collection doesn't include object.

#assert_not_includes
#assert_not_instance_of

Passes if object.instance_of?(klass) does not hold.

#assert_not_kind_of

Passes if object.kind_of?(klass) does not hold.

#assert_not_match

Passes if regexp !~ string

#assert_not_nil

Passes if ! object .nil?

#assert_not_operator

Compares the object1 with object2 using operator.

#assert_not_predicate

Passes if object.predicate is not true.

#assert_not_respond_to

Passes if object does not .respond_to? method.

#assert_not_same

Passes if ! actual .equal? expected

#assert_not_send

Passes if the method send doesn't return a true value.

#assert_nothing_raised

Passes if block does not raise an exception.

#assert_nothing_thrown

Passes if block does not throw anything.

#assert_operator

Compares the object1 with object2 using operator.

#assert_path_exist

Passes if path exists.

#assert_path_not_exist

Passes if path doesn't exist.

#assert_predicate

Passes if object.predicate is true.

#assert_raise

Passes if the block raises one of the expected exceptions.

#assert_raise_kind_of

Passes if the block raises one of the given exceptions or sub exceptions of the given exceptions.

#assert_raise_message

Passes if an exception is raised in block and its message is expected.

#assert_raises
#assert_respond_to

Passes if object .respond_to? method

#assert_same

Passes if actual .equal? expected (i.e.

#assert_send

Passes if the method send returns a true value.

#assert_throw

Passes if the block throws expected_object

#assert_throws
#assert_true

Passes if actual is true.

#build_message

Builds a failure message.

#flunk

Flunk always fails.

#refute

Asserts that object is false or nil.

#refute_empty
#refute_equal
#refute_in_delta
#refute_in_epsilon
#refute_includes
#refute_instance_of
#refute_kind_of
#refute_match
#refute_nil
#refute_operator
#refute_predicate
#refute_respond_to
#refute_same
#_assert_in_delta_message, #_assert_in_delta_validate_arguments, #_assert_in_epsilon_message, #_assert_in_epsilon_validate_arguments, #_assert_raise, #_set_failed_information, #_wrap_assertion

Priority - Included

TestCaseNotificationSupport - Included

#notify

Notify some information.

#add_notification

TestCaseOmissionSupport - Included

#omit

Omit the test or part of the test.

#omit_if

Omit the test or part of the test if condition is true.

#omit_unless

Omit the test or part of the test if condition is not true.

#add_omission

TestCasePendingSupport - Included

#pend

Marks the test or part of the test is pending.

#add_pending

FailureHandler - Included

ErrorHandler - Included

Fixture - Included

Attribute - Included

Constructor Details

.new(test_method_name) ⇒ TestCase

Creates a new instance of the fixture for running the test represented by test_method_name.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 461

def initialize(test_method_name)
  @method_name = test_method_name
  @internal_data = InternalData.new
end

Class Attribute Details

.test_order (rw)

Returns the current test order. This returns :alphabetic by default.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 251

def test_order
  ancestors.each do |ancestor|
    order = @@test_orders[ancestor]
    return order if order
  end
  AVAILABLE_ORDERS.first
end

.test_order=(order) (rw)

Sets the current test order.

Here are the available order:

:alphabetic

Default. Tests are sorted in alphabetic order.

:random

Tests are sorted in random order.

:defined

Tests are sorted in defined order.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 268

def test_order=(order)
  @@test_orders[self] = order
end

Class Method Details

.added_method_names

This method is for internal use only.
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 162

def added_method_names # :nodoc:
  (@@added_method_names[self] ||= {}).keys
end

.description(value, target = nil)

Describes a test.

The following example associates “register a normal user” description with “test_register” test.

description "register a normal user"
def test_register
  #...
end
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 331

def description(value, target=nil)
  targets = [target].compact
  attribute(:description, value, {}, *targets)
end

.find_locations(query)

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 397

def find_locations(query)
  query_path = query[:path]
  query_line = query[:line]
  query_method_name = query[:method_name]

  available_locations = target_method_locations(query_path)
  if query_line
    available_locations = available_locations.sort_by do |location|
      -location[:line]
    end
    available_location = available_locations.find do |location|
      query_line >= location[:line]
    end
    return [] if available_location.nil?
    return [] if available_location[:test_case] != self
    available_locations = [available_location]
  end
  if query_method_name
    available_location = available_locations.find do |location|
      location[:test_case] == self and
        query_method_name == location[:method_name]
    end
    return [] if available_location.nil?
    available_locations = [available_location]
  end

  available_locations
end

.inherited(sub_class)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 128

def inherited(sub_class) # :nodoc:
  DESCENDANTS << sub_class
  super
end

.method_added(name)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 134

def method_added(name) # :nodoc:
  super
  added_method_names = (@@added_method_names[self] ||= {})
  stringified_name = name.to_s
  if added_method_names.key?(stringified_name)
    attribute(:redefined, {:backtrace => caller}, {}, stringified_name)
  end
  source_location = find_attribute(stringified_name, :source_location)
  if source_location
    path, line = source_location
  elsif respond_to?(:caller_locations, true)
    location = caller_locations(1, 1)[0]
    path = location.absolute_path || location.path
    line = location.lineno
  else
    # TODO: Remove me when Ruby 1.9 support is dropped
    path, line, = caller[0].split(/:(\d+)/, 2)
    line = line.to_i if line
  end
  method_locations << {
    :method_name => stringified_name,
    :path => File.expand_path(path),
    :line => line,
  }
  added_method_names[stringified_name] = true
  AutoRunnerLoader.check(self, stringified_name)
end

.method_locations (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 430

def method_locations
  @@method_locations[self] ||= []
end

.shutdown

Called after every test case runs. Can be used to tear down fixture information used in test case scope.

Here is an example test case:

class TestMyClass < Test::Unit::TestCase
  class << self
    def shutdown
      #...
    end
  end

  def teardown
    #...
  end

  def test_my_class1
    #...
  end

  def test_my_class2
    #...
  end
end

Here is a call order:

  • test_my_class1 (or test_my_class2)

  • teardown

  • test_my_class2 (or test_my_class1)

  • teardown

  • shutdown

Note that you should not assume test order. Tests should be worked in any order.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 244

def shutdown
end

.startup

Called before every test case runs. Can be used to set up fixture information used in test case scope.

Here is an example test case:

class TestMyClass < Test::Unit::TestCase
  class << self
    def startup
      #...
    end
  end

  def setup
    #...
  end

  def test_my_class1
    #...
  end

  def test_my_class2
    #...
  end
end

Here is a call order:

  • startup

  • setup

  • test_my_class1 (or test_my_class2)

  • setup

  • test_my_class2 (or test_my_class1)

Note that you should not assume test order. Tests should be worked in any order.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 208

def startup
end

.sub_test_case(name) { ... } ⇒ TestCase

Defines a sub test case.

This is a syntax sugar. The both of the following codes are the same in meaning:

Standard:

class TestParent < Test::Unit::TestCase
  class TestChild < self
    def test_in_child
    end
  end
end

Syntax sugar:

class TestParent < Test::Unit::TestCase
  sub_test_case("TestChild") do
    def test_in_child
    end
  end
end

The difference of them are the following:

  • ::Test case created by sub_test_case is an anonymous class. So you can't refer the test case by name.

  • The class name of class style must follow constant naming rule in Ruby. But the name of test case created by sub_test_case doesn't need to follow the rule. For example, you can use a space in name such as “child test”.

Parameters:

  • name (String)

    The name of newly created sub test case.

Yields:

  • The block is evaluated under the newly created sub test case class context.

Returns:

  • (TestCase)

    Created sub test case class.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 371

def sub_test_case(name, &block)
  parent_test_case = self
  sub_test_case = Class.new(self) do
    singleton_class = class << self; self; end
    singleton_class.__send__(:define_method, :name) do
      [parent_test_case.name, name].compact.join("::")
    end
  end
  sub_test_case.class_eval(&block)
  sub_test_case
end

.suite

Rolls up all of the test* methods in the fixture into one suite, creating a new instance of the fixture for each method.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 169

def suite
  suite_creator = TestSuiteCreator.new(self)
  suite_creator.create
end

.target_method_locations(path) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 435

def target_method_locations(path)
  if path.nil?
    self_location = method_locations.first
    path = self_location[:path] if self_location
  end
  return [] if path.nil?

  target_locations = []
  @@method_locations.each do |test_case, locations|
    locations.each do |location|
      absolete_path = File.expand_path(path)
      location_path = location[:path]
      location_basename = File.basename(location_path)
      if location_path == absolete_path or location_basename == path
        target_locations << location.merge(:test_case => test_case)
      end
    end
  end
  target_locations
end

.test(*test_description_or_targets, &block)

Defines a test in declarative syntax or marks following method as a test method.

In declarative syntax usage, the following two test definitions are the almost same:

description "register user"
def test_register_user
  #...
end

test "register user" do
  #...
end

In test method mark usage, the “my_test_method” is treated as a test method:

test
def my_test_method
  assert_equal("call me", ...)
end
[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 294

def test(*test_description_or_targets, &block)
  if block_given?
    test_description = test_description_or_targets.first
    if test_description.nil?
      raise ArgumentError, "test description is missing"
    end
    n_arguments = test_description_or_targets.size
    if n_arguments > 1
      message = "wrong number of arguments (#{n_arguments} for 1)"
      raise ArgumentError, message
    end
    method_name = "test: #{test_description}"
    description(test_description, method_name)
    attribute(:test, true, {}, method_name)
    if block.respond_to?(:source_location)
      attribute(:source_location, block.source_location, {}, method_name)
    end
    define_method(method_name, &block)
  else
    targets = test_description_or_targets
    attribute(:test, true, {}, *targets)
    targets.each do |target|
      AutoRunnerLoader.check(self, target)
    end
  end
end

.test_defined?(query) ⇒ Boolean

Checks whether a test that is matched the query is defined.

Parameters:

  • query (Hash)

    a customizable set of options

Options Hash (query):

  • :path (String) — default: nil

    the path where a test is defined in.

  • :line (Numeric) — default: nil

    the line number where a test is defined at.

  • :method_name (String) — default: nil

    the method name for a test.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 392

def test_defined?(query)
  locations = find_locations(query)
  not locations.empty?
end

Instance Attribute Details

#interrupted?Boolean (readonly)

Returns whether the test is interrupted.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 733

def interrupted?
  @internal_data.interrupted?
end

#method_name (readonly)

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 457

attr_reader :method_name

#passed?Boolean (readonly)

Returns whether this individual test passed or not. Primarily for use in teardown so that artifacts can be left behind if the test fails.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 740

def passed?
  @internal_data.passed?
end

#valid?Boolean (readonly)

This method is for internal use only.

Returns the test is valid test. It is used in internal.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 472

def valid? # :nodoc:
  return false unless respond_to?(@method_name)
  test_method = method(@method_name)
  unless @internal_data.have_test_data?
    return false unless test_method.arity <= 0
  end
  owner = Util::MethodOwnerFinder.find(self, @method_name)
  if owner.class != Module and self.class != owner
    return false
  end
  true
end

Instance Method Details

#==(other)

It's handy to be able to compare TestCase instances.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 715

def ==(other)
  return false unless other.kind_of?(self.class)
  return false unless @method_name == other.method_name
  return false unless data_label == other.data_label
  self.class == other.class
end

#add_assertion (private)

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 809

def add_assertion
  current_result.add_assertion
end

#add_passvoid

This method returns an undefined value.

Notify that the test is passed. Normally, it is not needed because #run calls it automatically. If you want to override #run, it is not a good idea. Please contact test-unit developers. We will help you without your custom #run. For example, we may add a new hook in #run.

This is a public API for developers who extend test-unit.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 764

def add_pass
  current_result.add_pass
end

#assign_test_data(label, data)

This method is for internal use only.

Assigns test data to the test. It is used in internal.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 467

def assign_test_data(label, data) # :nodoc:
  @internal_data.assign_test_data(label, data)
end

#cleanup

Called after every test method runs but the test method isn't marked as 'passed'. Can be used to clean up and/or verify tested condition. e.g. Can be used to verify mock.

You can add additional cleanup tasks by the following code:

class TestMyClass < Test::Unit::TestCase
  def cleanup
    #...
  end

  cleanup
  def my_cleanup1
    #...
  end

  cleanup do
    #... # cleanup callback1
  end

  cleanup
  def my_cleanup2
    #...
  end

  cleanup do
    #... # cleanup callback2
  end

  def test_my_class
    #...
  end
end

Here is a call order:

  • test_my_class

  • cleanup callback2

  • my_cleanup2

  • cleanup callback1

  • my_cleanup1

  • cleanup

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 620

def cleanup
end

#current_result (private)

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 769

def current_result
  @_result
end

#data_label

Returns a label of test data for the test. If the test isn't associated with any test data, it returns nil.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 677

def data_label
  @internal_data.test_data_label
end

#default_test

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 666

def default_test
  flunk("No tests were specified")
end

#description

Returns a description for the test. A description will be associated by .test or .description.

Returns a name for the test for no description test.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 705

def description
  self[:description] || name
end

#elapsed_time

Returns elapsed time for the test was ran.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 728

def elapsed_time
  @internal_data.elapsed_time
end

#handle_exception(exception) (private)

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 797

def handle_exception(exception)
  self.class.exception_handlers.each do |handler|
    if handler.respond_to?(:call)
      handled = handler.call(self, exception)
    else
      handled = __send__(handler, exception)
    end
    return true if handled
  end
  false
end

#local_name

Returns a human-readable name for the specific test that this instance of TestCase represents.

#local_name doesn't include class name. #name includes class name.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 692

def local_name
  if @internal_data.have_test_data?
    "#{@method_name}[#{data_label}]"
  else
    @method_name.to_s
  end
end

#name

Returns a human-readable name for the specific test that this instance of TestCase represents.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 683

def name
  "#{local_name}(#{self.class.name})"
end

#problem_occurredvoid

This method returns an undefined value.

Notify that a problem is occurred in the test. It means that the test is a failed test. If any failed tests exist in test suites, the test process exits with failure exit status.

This is a public API for developers who extend test-unit.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 751

def problem_occurred
  @internal_data.problem_occurred
end

#run(result)

Runs the individual test method represented by this instance of the fixture, collecting statistics, failures and errors in result.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 488

def run(result)
  begin
    @_result = result
    @internal_data.test_started
    yield(STARTED, name)
    yield(STARTED_OBJECT, self)
    processed_exception_in_setup = false
    begin
      catch do |tag|
        run_setup do
          begin
            run_test
            run_cleanup
            add_pass
          rescue Exception
            @internal_data.interrupted
            unless handle_exception($!)
              processed_exception_in_setup = true
              raise
            end
            throw(tag)
          end
        end
      end
    rescue Exception
      if processed_exception_in_setup
        raise
      else
        @internal_data.interrupted
        raise unless handle_exception($!)
      end
    ensure
      begin
        run_teardown
      rescue Exception
        raise unless handle_exception($!)
      end
    end
    @internal_data.test_finished
    result.add_run
    yield(FINISHED, name)
    yield(FINISHED_OBJECT, self)
  ensure
    # @_result = nil # For test-spec's after_all :<
  end
end

#run_test (private)

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 773

def run_test
  signature = "#{self.class}\##{@method_name}"
  redefined_info = self[:redefined]
  if redefined_info
    notify("<#{signature}> was redefined",
           :backtrace => redefined_info[:backtrace])
  end
  if @internal_data.have_test_data?
    test_method = method(@method_name)
    if test_method.arity == 1 or test_method.arity < 0
      __send__(@method_name, @internal_data.test_data)
    else
      locations = self.class.find_locations(:method_name => @method_name)
      backtrace = locations.collect do |location|
        "#{location[:path]}:#{location[:line]}"
      end
      notify("<#{signature}> misses a parameter to take test data",
             :backtrace => backtrace)
    end
  else
    __send__(@method_name)
  end
end

#setup

Called before every test method runs. Can be used to set up fixture information.

You can add additional setup tasks by the following code:

class TestMyClass < Test::Unit::TestCase
  def setup
    #...
  end

  setup
  def my_setup1
    #...
  end

  setup do
    #... # setup callback1
  end

  setup
  def my_setup2
    #...
  end

  setup do
    #... # setup callback2
  end

  def test_my_class
    #...
  end
end

Here is a call order:

  • setup

  • my_setup1

  • setup callback1

  • my_setup2

  • setup callback2

  • test_my_class

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 575

def setup
end

#size

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 670

def size
  1
end

#start_time

Returns a Time at the test was started.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 723

def start_time
  @internal_data.start_time
end

#teardown

Called after every test method runs. Can be used to tear down fixture information.

You can add additional teardown tasks by the following code:

class TestMyClass < Test::Unit::TestCase
  def teardown
    #...
  end

  teardown
  def my_teardown1
    #...
  end

  teardown do
    #... # teardown callback1
  end

  teardown
  def my_teardown2
    #...
  end

  teardown do
    #... # teardown callback2
  end

  def test_my_class
    #...
  end
end

Here is a call order:

  • test_my_class

  • teardown callback2

  • my_teardown2

  • teardown callback1

  • my_teardown1

  • teardown

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 663

def teardown
end

#to_s

Overridden to return #name.

[ GitHub ]

  
# File 'lib/test/unit/testcase.rb', line 710

def to_s
  name
end