class Test::Unit::TestCase

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 Test::Unit::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

Attributes

method_name[R]

Public Class Methods

description(value, target=nil) click to toggle source

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
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 374
def description(value, target=nil)
  targets = [target].compact
  attribute(:description, value, {}, *targets)
end
find_locations(query) click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 466
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
new(test_method_name) click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 553
def initialize(test_method_name)
  @method_name = test_method_name
  @internal_data = InternalData.new
end
parallel_safe?() click to toggle source

Indicates whether the test is parallel safe.

Tests that this method returns ‘false` are executed sequentially before parallel safe tests run. This only works when the `–parallel` option is specified.

@example Indicates that test_parallel_unsafe is parallel unsafe

class TestMyClass < Test::Unit::TestCase
  class << self
    def parallel_safe?
      false
    end
  end

  def test_parallel_unsafe
    # ...
  end
end

@since 3.6.3

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 149
def parallel_safe?
  true
end
ractor(options={}) click to toggle source

Declares that the following test uses Ractor.

Tests that use Ractor are executed at the end. Because multi Ractor mode is enabled in the current process and it’s not disabled even when only one Ractor is running after running a test that uses Ractor on Ruby 3.0. It will be solved in the future.

This is implemented by setting the ‘:ractor` attribute of the test to `true`.

@param options [Hash] See {Attribute::ClassMethods#attribute}

for details.

@return [void]

@example Declares that test_do_something_with_ractor uses Ractor

ractor
def test_do_something_with_ractor
  Ractor.new do
    # ...
  end
end

@since 3.4.6

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 405
def ractor(options={})
  attribute(:ractor, true, options)
end
shutdown() click to toggle source

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.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 284
def shutdown
end
startup() click to toggle source

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.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 246
def startup
end
sub_test_case(name, &block) click to toggle source

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”.

@param name [String] The name of newly created sub test case. @yield

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

@return [Test::Unit::TestCase] Created sub test case class.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 446
def sub_test_case(name, &block)
  sub_test_case = sub_test_case_class(name)
  sub_test_case.class_eval(&block)
  sub_test_case
end
suite() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 205
def suite
  suite_creator = TestSuiteCreator.new(self)
  suite_creator.create
end
test(*test_description_or_targets, &block) click to toggle source

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
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 337
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) click to toggle source

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

@option query [String] :path (nil)

the path where a test is defined in.

@option query [Numeric] :line (nil)

the line number where a test is defined at.

@option query [String] :method_name (nil)

the method name for a test.
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 461
def test_defined?(query)
  locations = find_locations(query)
  not locations.empty?
end
test_order() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 291
def test_order
  ancestors.each do |ancestor|
    order = @@test_orders[ancestor]
    return order if order
  end
  AVAILABLE_ORDERS.first
end
test_order=(order) click to toggle source

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.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 311
def test_order=(order)
  @@test_orders[self] = order
end

Private Class Methods

add_method_location(location) click to toggle source

@private

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 507
def add_method_location(location)
  @@method_location_mutex.synchronize do
    method_locations << location
  end
end
method_locations() click to toggle source

@private

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 502
def method_locations
  @@method_locations[self] ||= []
end
sub_test_case_class(name) click to toggle source

@private

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 538
def sub_test_case_class(name)
  parent_test_case = self
  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
end
target_method_locations(path) click to toggle source

@private

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 514
def target_method_locations(path)
  @@method_location_mutex.synchronize do
    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
end

Public Instance Methods

==(other) click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 819
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_pass() click to toggle source

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.

@return [void]

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 868
def add_pass
  current_result.add_pass
end
cleanup() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 716
def cleanup
end
data() click to toggle source

Returns test data for the test. If the test isn’t associated with any test data, it returns ‘nil`.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 781
def data
  @internal_data.test_data
end
data_label() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 775
def data_label
  @internal_data.test_data_label
end
default_test() click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 764
def default_test
  flunk("No tests were specified")
end
description() click to toggle source

Returns a description for the test. A description will be associated by Test::Unit::TestCase.test or Test::Unit::TestCase.description.

Returns a name for the test for no description test.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 809
def description
  self[:description] || name
end
elapsed_time() click to toggle source

Returns elapsed time for the test was ran.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 832
def elapsed_time
  @internal_data.elapsed_time
end
interrupted?() click to toggle source

Returns whether the test is interrupted.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 837
def interrupted?
  @internal_data.interrupted?
end
local_name() click to toggle source

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.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 796
def local_name
  if @internal_data.have_test_data?
    "#{@method_name}[#{data_label}]"
  else
    @method_name.to_s
  end
end
name() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 787
def name
  "#{local_name}(#{self.class.name})"
end
passed?() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 844
def passed?
  @internal_data.passed?
end
problem_occurred() click to toggle source

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.

@return [void]

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 855
def problem_occurred
  @internal_data.problem_occurred
end
run(result, runner: nil) { |STARTED, name| ... } click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 580
def run(result, runner: nil)
  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
setup() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 669
def setup
end
size() click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 768
def size
  1
end
start_time() click to toggle source

Returns a Time at the test was started.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 827
def start_time
  @internal_data.start_time
end
teardown() click to toggle source

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

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 761
def teardown
end
to_s() click to toggle source

Overridden to return name.

# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 814
def to_s
  name
end

Private Instance Methods

add_assertion() click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 912
def add_assertion
  current_result.add_assertion
end
current_result() click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 873
def current_result
  @_result
end
handle_exception(exception) click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 900
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
run_test() click to toggle source
# File test-unit-3.6.4/lib/test/unit/testcase.rb, line 877
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 self[:ractor] and not defined?(::Ractor)
    omit("<#{signature}> requires Ractor")
  end
  if @internal_data.have_test_data?
    test_method = method(@method_name)
    arity = test_method.arity
    if arity.zero?
      __send__(@method_name)
    else
      __send__(@method_name, @internal_data.test_data)
    end
  else
    __send__(@method_name)
  end
end