Class: Tryouts::TestBatch

Inherits:
Object
  • Object
show all
Defined in:
lib/tryouts/test_batch.rb

Overview

Modern TestBatch using Ruby 3.4+ patterns and formatter system

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(testrun, **options) ⇒ TestBatch

Returns a new instance of TestBatch.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/tryouts/test_batch.rb', line 27

def initialize(testrun, **options)
  @testrun         = testrun
  @container       = Object.new
  @options         = options
  @formatter       = Tryouts::CLI::FormatterFactory.create_formatter(options)
  @output_manager  = options[:output_manager]
  @global_tally    = options[:global_tally]
  @failed_count    = 0
  @status          = :pending
  @results         = []
  @start_time      = nil
  @test_case_count = 0
  @setup_failed    = false
  @line_spec       = options[:line_spec]  # For output filtering only

  # Setup container for fresh context mode - preserves @instance_variables from setup
  @setup_container = nil

  # Circuit breaker for batch-level failure protection
  @consecutive_failures     = 0
  @max_consecutive_failures = options[:max_consecutive_failures] || 10
  @circuit_breaker_active   = false

  # Expose context objects for testing - different strategies for each mode
  @shared_context = if options[:shared_context]
                      @container  # Shared mode: single container reused across tests
                    else
                      FreshContextFactory.new  # Fresh mode: factory that creates new containers
                    end
end

Instance Attribute Details

#containerObject (readonly)

Returns the value of attribute container.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def container
  @container
end

#failed_countObject (readonly)

Returns the value of attribute failed_count.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def failed_count
  @failed_count
end

#formatterObject (readonly)

Returns the value of attribute formatter.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def formatter
  @formatter
end

#output_managerObject (readonly)

Returns the value of attribute output_manager.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def output_manager
  @output_manager
end

#resultsObject (readonly)

Returns the value of attribute results.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def results
  @results
end

#statusObject (readonly)

Returns the value of attribute status.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def status
  @status
end

#testrunObject (readonly)

Returns the value of attribute testrun.



25
26
27
# File 'lib/tryouts/test_batch.rb', line 25

def testrun
  @testrun
end

Instance Method Details

#completed?Boolean

Returns:

  • (Boolean)


168
169
170
# File 'lib/tryouts/test_batch.rb', line 168

def completed?
  @status == :completed
end

#empty?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/tryouts/test_batch.rb', line 148

def empty?
  @testrun.empty?
end

#failed?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'lib/tryouts/test_batch.rb', line 164

def failed?
  @failed_count > 0
end

#pathObject



160
161
162
# File 'lib/tryouts/test_batch.rb', line 160

def path
  @testrun.source_file
end

#run(before_test_hook = nil) ⇒ Object

Main execution pipeline using functional composition



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/tryouts/test_batch.rb', line 59

def run(before_test_hook = nil, &)
  return false if empty?

  @start_time      = Time.now
  @test_case_count = test_cases.size

  @output_manager&.execution_phase(@test_case_count)
  @output_manager&.info("Context: #{@options[:shared_context] ? 'shared' : 'fresh'}", 1)
  @output_manager&.file_start(path, context: @options[:shared_context] ? :shared : :fresh)

  if shared_context?
    @output_manager&.info('Running global setup...', 2)
    execute_global_setup

    # Stop execution if setup failed
    if @setup_failed
      @output_manager&.error('Stopping batch execution due to setup failure')
      @status = :failed
      finalize_results([])
      return false
    end
  else
    # Fresh context mode: execute setup once to establish shared @instance_variables
    @output_manager&.info('Running setup for fresh context...', 2)
    execute_fresh_context_setup

    # Stop execution if setup failed
    if @setup_failed
      @output_manager&.error('Stopping batch execution due to setup failure')
      @status = :failed
      finalize_results([])
      return false
    end
  end

  idx               = 0
  execution_results = test_cases.map do |test_case|
    @output_manager&.trace("Test #{idx + 1}/#{@test_case_count}: #{test_case.description}", 2)
    idx += 1

    # Check circuit breaker before executing test
    if @circuit_breaker_active
      @output_manager&.error("Circuit breaker active - skipping remaining tests after #{@consecutive_failures} consecutive failures")
      break
    end

    # Apply line_spec filter for output notifications (test_start/test_end)
    # but still execute ALL tests regardless of filter
    if should_display_test_result?(test_case)
      @output_manager&.test_start(test_case, idx, @test_case_count)
    end

    result = execute_single_test(test_case, before_test_hook, &) # runs the test code

    if should_display_test_result?(test_case)
      @output_manager&.test_end(test_case, idx, @test_case_count)
    end

    # Update circuit breaker state based on result
    update_circuit_breaker(result)

    result
  rescue StandardError => ex
    if should_display_test_result?(test_case)
      @output_manager&.test_end(test_case, idx, @test_case_count)
    end
    # Create error result packet to maintain consistent data flow
    error_result = build_error_result(test_case, ex)
    process_test_result(error_result)

    # Update circuit breaker for exception cases
    update_circuit_breaker(error_result)

    error_result
  end

  # Used for a separate purpose then execution_phase.
  # e.g. the quiet formatter prints a newline after all test dots
  @output_manager&.file_end(path, context: @options[:shared_context] ? :shared : :fresh)

  @output_manager&.execution_phase(test_cases.size)

  execute_global_teardown
  finalize_results(execution_results)

  @status = :completed
  !failed?
end

#sizeObject



152
153
154
# File 'lib/tryouts/test_batch.rb', line 152

def size
  @testrun.total_tests
end

#test_casesObject



156
157
158
# File 'lib/tryouts/test_batch.rb', line 156

def test_cases
  @testrun.test_cases
end