You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If setup_class raises a regular exception and the test class's on_fail then calls asserts.abort_all(), the setup_class ERROR record is added to the in-memory TestResult but never dumped to the summary file. The resulting test_summary.yaml contains the SKIP records for the class's tests and a final Summary entry with Error: 1, but no RECORD entry accounting for that error.
Expected:test_summary.yaml contains a RECORD with Test Name: setup_class, Result: ERROR, followed by a SKIP record for test_1 and a Summary with Error: 1, Skipped: 1.
Actual: The setup_class RECORD is missing. The SKIP record and Summary (Error: 1, Skipped: 1) are present, so the file is internally inconsistent — one error is counted but no record describes it. Downstream YAML consumers that key on the setup_class record (e.g. to classify a run failure) never see it.
Cause
In BaseTestClass._setup_class, the abort raised from on_fail propagates out of _exec_procedure_func before the record is written:
exceptExceptionase:
logging.exception('Error in %s#setup_class.', self.TAG)
class_record.test_error(e)
self.results.add_class_error(class_record) # in-memory onlyself._exec_procedure_func(self._on_fail, class_record) # TestAbortAll escapes hereclass_record.update_record() # not reachedself.summary_writer.dump( # not reachedclass_record.to_dict(), records.TestSummaryEntryType.RECORD
)
self._skip_remaining_tests(e) # not reachedreturnself.results
Control then lands in run()'s except signals.TestAbortAll, which calls _skip_remaining_tests (so the SKIP records are dumped) and re-raises.
The expects.recorder.has_error branch immediately below has the same ordering and the same problem.
History
Fix behaviors for abort_all related to setup_class. #461 (63b8e3f, 2018-06-12) — commit message: "A record for setup_class should exist if setup_class failed and abort_all is called in on_fail." The diff deliberately moved the summary_writer.dump(...) call before_exec_procedure_func(self._on_fail, ...). Added test_abort_all_in_on_fail_from_setup_class.
Fix expects for different test stages. #531 (e8ab13f, 2018-10-15) — moved the logic into _setup_class and, to include update_record() after on_fail, placed the dump after the on_fail call again, reintroducing the issue.
The regression test from #461 did not catch this because it only asserts on the in-memory bt_cls.results.error[0], not on what was written via summary_writer.
Suggested fix
Mirror the structure already used in exec_one_test, where update_record() runs first and the dump lives in a finally around the procedure call:
Apply the same try/finally to the expects.recorder.has_error branch.
Also suggest extending test_abort_all_in_on_fail_from_setup_class to assert that summary_writer.dump was called with a record whose test_name == 'setup_class', so the file-level behavior is covered.
Environment
Reproduced against master (mobly/base_test.py as of the date of filing).
Summary
If
setup_classraises a regular exception and the test class'son_failthen callsasserts.abort_all(), thesetup_classERROR record is added to the in-memoryTestResultbut never dumped to the summary file. The resultingtest_summary.yamlcontains the SKIP records for the class's tests and a final Summary entry withError: 1, but no RECORD entry accounting for that error.This was explicitly fixed in #461 (63b8e3f) and regressed in #531 (e8ab13f).
Reproduction
Expected:
test_summary.yamlcontains a RECORD withTest Name: setup_class,Result: ERROR, followed by a SKIP record fortest_1and a Summary withError: 1, Skipped: 1.Actual: The
setup_classRECORD is missing. The SKIP record and Summary (Error: 1, Skipped: 1) are present, so the file is internally inconsistent — one error is counted but no record describes it. Downstream YAML consumers that key on thesetup_classrecord (e.g. to classify a run failure) never see it.Cause
In
BaseTestClass._setup_class, the abort raised fromon_failpropagates out of_exec_procedure_funcbefore the record is written:Control then lands in
run()'sexcept signals.TestAbortAll, which calls_skip_remaining_tests(so the SKIP records are dumped) and re-raises.The
expects.recorder.has_errorbranch immediately below has the same ordering and the same problem.History
abort_allrelated tosetup_class. #461 (63b8e3f, 2018-06-12) — commit message: "A record forsetup_classshould exist ifsetup_classfailed andabort_allis called inon_fail." The diff deliberately moved thesummary_writer.dump(...)call before_exec_procedure_func(self._on_fail, ...). Addedtest_abort_all_in_on_fail_from_setup_class.expectsfor different test stages. #531 (e8ab13f, 2018-10-15) — moved the logic into_setup_classand, to includeupdate_record()afteron_fail, placed the dump after theon_failcall again, reintroducing the issue.The regression test from #461 did not catch this because it only asserts on the in-memory
bt_cls.results.error[0], not on what was written viasummary_writer.Suggested fix
Mirror the structure already used in
exec_one_test, whereupdate_record()runs first and the dump lives in afinallyaround the procedure call:Apply the same
try/finallyto theexpects.recorder.has_errorbranch.Also suggest extending
test_abort_all_in_on_fail_from_setup_classto assert thatsummary_writer.dumpwas called with a record whosetest_name == 'setup_class', so the file-level behavior is covered.Environment
Reproduced against
master(mobly/base_test.pyas of the date of filing).