Class: Test::Unit::TestCase

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

Defined Under Namespace

Classes: InternalData

Constant Summary collapse

STARTED =

:nodoc:

name + "::STARTED"
FINISHED =

:nodoc:

name + "::FINISHED"
STARTED_OBJECT =

:nodoc:

name + "::STARTED::OBJECT"
FINISHED_OBJECT =

:nodoc:

name + "::FINISHED::OBJECT"
DESCENDANTS =

:nodoc:

[]
AVAILABLE_ORDERS =

:nodoc:

[:alphabetic, :random, :defined]
@@added_method_names =
{}
@@test_orders =
{}

Constants included from Util::BacktraceFilter

Util::BacktraceFilter::POWERASSERT_PREFIX, Util::BacktraceFilter::TESTUNIT_FILE_SEPARATORS, Util::BacktraceFilter::TESTUNIT_PREFIX, Util::BacktraceFilter::TESTUNIT_RB_FILE

Constants included from Assertions

Assertions::NOT_SPECIFIED

Constants included from ErrorHandler

ErrorHandler::NOT_PASS_THROUGH_EXCEPTIONS, ErrorHandler::NOT_PASS_THROUGH_EXCEPTION_NAMES, ErrorHandler::PASS_THROUGH_EXCEPTIONS, ErrorHandler::PASS_THROUGH_EXCEPTION_NAMES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::Output

#capture_output

Methods included from Util::BacktraceFilter

filter_backtrace

Methods included from Assertions

#assert, #assert_alias_method, #assert_all, #assert_block, #assert_boolean, #assert_compare, #assert_const_defined, #assert_empty, #assert_equal, #assert_fail_assertion, #assert_false, #assert_in_delta, #assert_in_epsilon, #assert_include, #assert_instance_of, #assert_kind_of, #assert_match, #assert_nil, #assert_no_match, #assert_not_const_defined, #assert_not_empty, #assert_not_equal, #assert_not_in_delta, #assert_not_in_epsilon, #assert_not_include, #assert_not_instance_of, #assert_not_kind_of, #assert_not_match, #assert_not_nil, #assert_not_operator, #assert_not_predicate, #assert_not_respond_to, #assert_not_same, #assert_not_send, #assert_nothing_leaked_memory, #assert_nothing_raised, #assert_nothing_thrown, #assert_operator, #assert_path_exist, #assert_path_not_exist, #assert_predicate, #assert_raise, #assert_raise_kind_of, #assert_raise_message, #assert_raise_with_message, #assert_respond_to, #assert_same, #assert_send, #assert_throw, #assert_true, #build_message, #flunk, #refute, use_pp=

Methods included from Data

included

Methods included from Priority

available_values, default, default=, disable, enable, enabled?, included, #priority_setup, #priority_teardown

Methods included from TestCaseNotificationSupport

included, #notify

Methods included from TestCaseOmissionSupport

included, #omit, #omit_if, #omit_unless

Methods included from TestCasePendingSupport

included, #pend

Methods included from FailureHandler

#add_failure, included

Methods included from ErrorHandler

included

Methods included from ExceptionHandler

exception_handlers, included

Methods included from Fixture

included

Methods included from Attribute

#[], #attributes, included

Constructor Details

#initialize(test_method_name) ⇒ TestCase

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



588
589
590
591
# File 'lib/test/unit/testcase.rb', line 588

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

Instance Attribute Details

#method_nameObject (readonly)

Returns the value of attribute method_name.



584
585
586
# File 'lib/test/unit/testcase.rb', line 584

def method_name
  @method_name
end

Class Method Details

.added_method_namesObject

:nodoc:



198
199
200
# File 'lib/test/unit/testcase.rb', line 198

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

.description(value, target = nil) ⇒ Object

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


374
375
376
377
# File 'lib/test/unit/testcase.rb', line 374

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

.find_locations(query) ⇒ Object



475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
# File 'lib/test/unit/testcase.rb', line 475

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

.include(*modules, &block) ⇒ Object

:nodoc:



158
159
160
161
162
163
164
165
166
# File 'lib/test/unit/testcase.rb', line 158

def include(*modules, &block) # :nodoc:
  result = super
  modules.each do |mod|
    mod.public_instance_methods(false).each do |method_name|
      AutoRunnerLoader.check(self, method_name.to_s)
    end
  end
  result
end

.inherited(sub_class) ⇒ Object

:nodoc:



153
154
155
156
# File 'lib/test/unit/testcase.rb', line 153

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

.method_added(name) ⇒ Object

:nodoc:



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/test/unit/testcase.rb', line 169

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
  location = {
    :method_name => stringified_name,
    :path => File.expand_path(path),
    :line => line,
  }
  add_method_location(location)
  added_method_names[stringified_name] = true
  AutoRunnerLoader.check(self, stringified_name)
end

.parallel_safe?Boolean

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.

Examples:

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

Returns:

  • (Boolean)

Since:

  • 3.6.3



149
150
151
# File 'lib/test/unit/testcase.rb', line 149

def parallel_safe?
  true
end

.ractor(options = {}) ⇒ void

This method returns an undefined value.

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.

Examples:

Declares that test_do_something_with_ractor uses Ractor


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

Declares that test_do_something_with_ractor uses Ractor in one line


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

Parameters:

Since:

  • 3.4.6



413
414
415
# File 'lib/test/unit/testcase.rb', line 413

def ractor(options={})
  attribute(:ractor, true, options)
end

.shutdownObject

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.



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

def shutdown
end

.startupObject

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.



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

def startup
end

.sub_test_case(name) { ... } ⇒ Test::Unit::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 backed by an anonymous class, but it is assigned to an auto generated constant. So it can be referred to by name (e.g. for Marshal.dump and across process use).

  • 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:



455
456
457
458
459
# File 'lib/test/unit/testcase.rb', line 455

def sub_test_case(name, &block)
  sub_test_case = sub_test_case_class(name)
  sub_test_case.class_eval(&block)
  sub_test_case
end

.suiteObject

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



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

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

.test(*test_description_or_targets, &block) ⇒ Object

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


337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File '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) ⇒ 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.

Returns:

  • (Boolean)


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

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

.test_orderObject

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



291
292
293
294
295
296
297
# File '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) ⇒ Object

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.



311
312
313
# File 'lib/test/unit/testcase.rb', line 311

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

.worker_idInteger

Returns a current worker ID for the test case. This return depends on how tests are run:

* Sequential: always returns `0`

* Parallel: returns a one-based to the number of workers.

Returns:

  • (Integer)

Since:

  • 3.7.4



514
515
516
# File 'lib/test/unit/testcase.rb', line 514

def worker_id
  @worker_id || 0
end

.worker_id=(worker_id) ⇒ Object

:nodoc:



518
519
520
# File 'lib/test/unit/testcase.rb', line 518

def worker_id=(worker_id) # :nodoc:
  @worker_id = worker_id
end

Instance Method Details

#==(other) ⇒ Object

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



875
876
877
878
879
880
# File 'lib/test/unit/testcase.rb', line 875

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



929
930
931
# File 'lib/test/unit/testcase.rb', line 929

def add_pass
  current_result.add_pass
end

#assign_test_data(label, data) ⇒ Object

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



594
595
596
# File 'lib/test/unit/testcase.rb', line 594

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

#cleanupObject

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



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

def cleanup
end

#dataObject

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



837
838
839
# File 'lib/test/unit/testcase.rb', line 837

def data
  @internal_data.test_data
end

#data_labelObject

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



831
832
833
# File 'lib/test/unit/testcase.rb', line 831

def data_label
  @internal_data.test_data_label
end

#default_testObject



810
811
812
# File 'lib/test/unit/testcase.rb', line 810

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

#descriptionObject

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.



865
866
867
# File 'lib/test/unit/testcase.rb', line 865

def description
  self[:description] || name
end

#elapsed_timeObject

Returns elapsed time for the test was ran.



888
889
890
# File 'lib/test/unit/testcase.rb', line 888

def elapsed_time
  @internal_data.elapsed_time
end

#interrupted?Boolean

Returns whether the test is interrupted.

Returns:

  • (Boolean)


893
894
895
# File 'lib/test/unit/testcase.rb', line 893

def interrupted?
  @internal_data.interrupted?
end

#local_nameObject

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.



852
853
854
855
856
857
858
# File 'lib/test/unit/testcase.rb', line 852

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

#marshal_dumpObject



933
934
935
936
937
938
# File 'lib/test/unit/testcase.rb', line 933

def marshal_dump
  {
    method_name: @method_name,
    internal_data: @internal_data,
  }
end

#marshal_load(data) ⇒ Object



940
941
942
943
# File 'lib/test/unit/testcase.rb', line 940

def marshal_load(data)
  @method_name = data[:method_name]
  @internal_data = data[:internal_data]
end

#nameObject

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



843
844
845
# File 'lib/test/unit/testcase.rb', line 843

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

#passed?Boolean

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

Returns:

  • (Boolean)


900
901
902
# File 'lib/test/unit/testcase.rb', line 900

def passed?
  @internal_data.passed?
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.



911
912
913
# File 'lib/test/unit/testcase.rb', line 911

def problem_occurred
  @internal_data.problem_occurred
end

#run(worker_context) ⇒ Object

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



615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# File 'lib/test/unit/testcase.rb', line 615

def run(worker_context)
  begin
    unless worker_context.is_a?(WorkerContext)
      result = worker_context
      worker_context = WorkerContext.new(nil, nil, result)
    end
    result = worker_context.result
    @_result = result
    instance_variables_before = instance_variables
    @internal_data.run_context = worker_context.run_context
    @internal_data.worker_id = worker_context.id
    @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 :<
    (instance_variables - instance_variables_before).each do |name|
      remove_instance_variable(name)
    end
  end
end

#runner_classObject

Returns test suite runner class for easy to test.



916
917
918
# File 'lib/test/unit/testcase.rb', line 916

def runner_class
  @internal_data.run_context.runner_class
end

#setupObject

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



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

def setup
end

#sizeObject



814
815
816
# File 'lib/test/unit/testcase.rb', line 814

def size
  1
end

#start_timeObject

Returns a Time at the test was started.



883
884
885
# File 'lib/test/unit/testcase.rb', line 883

def start_time
  @internal_data.start_time
end

#teardownObject

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



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

def teardown
end

#to_sObject

Overridden to return #name.



870
871
872
# File 'lib/test/unit/testcase.rb', line 870

def to_s
  name
end

#valid?Boolean

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

Returns:

  • (Boolean)


599
600
601
602
603
604
605
606
607
608
609
610
# File 'lib/test/unit/testcase.rb', line 599

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

#worker_idInteger

Returns a current worker ID for the test. See worker_id for details.

Returns:

  • (Integer)

Since:

  • 3.7.4



824
825
826
# File 'lib/test/unit/testcase.rb', line 824

def worker_id
  @internal_data.worker_id || 0
end