class Test::Unit::TestCase - test-unit: Ruby Standard Library Documentation

# 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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/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.7/lib/test/unit/testcase.rb, line 855
    def problem_occurred
      @internal_data.problem_occurred
    end

run(result, runner_class: 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.7/lib/test/unit/testcase.rb, line 580
    def run(result, runner_class: 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.7/lib/test/unit/testcase.rb, line 669
    def setup
    end

size() click to toggle source

    # File test-unit-3.6.7/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.7/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.7/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.7/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.7/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.7/lib/test/unit/testcase.rb, line 873
    def current_result
      @_result
    end

handle_exception(exception) click to toggle source

    # File test-unit-3.6.7/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.7/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