Skip to content

Commit 5695d99

Browse files
committed
Prevent duplicate setUp & tearDown; plus refactoring
1 parent 6f4f4ab commit 5695d99

File tree

1 file changed

+128
-46
lines changed

1 file changed

+128
-46
lines changed

seleniumbase/fixtures/base_case.py

Lines changed: 128 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ def __init__(self, *args, **kwargs):
6767
self.driver = None
6868
self.environment = None
6969
self.env = None # Add a shortened version of self.environment
70+
self.__called_setup = False
71+
self.__called_teardown = False
72+
self.__start_time_ms = None
73+
self.__passed_then_skipped = False
7074
self.__last_url_of_deferred_assert = "data:,"
7175
self.__last_page_load_url = "data:,"
7276
self.__last_page_screenshot = None
@@ -3748,6 +3752,12 @@ def skip(self, reason=""):
37483752
self.__check_scope()
37493753
if self.dashboard or (self.is_pytest and self.with_db_reporting):
37503754
test_id = self.__get_test_id_2()
3755+
if (
3756+
test_id in sb_config._results.keys()
3757+
and sb_config._results[test_id] == "Passed"
3758+
):
3759+
# Duplicate tearDown() called where test already passed
3760+
self.__passed_then_skipped = True
37513761
sb_config._results[test_id] = "Skipped"
37523762
self.__skip_reason = reason
37533763
elif reason and not self.is_pytest:
@@ -7336,6 +7346,11 @@ def setUp(self, masterqa_mode=False):
73367346
You'll need to add the following line to the subclass setUp() method:
73377347
super(SubClassOfBaseCase, self).setUp()
73387348
"""
7349+
if not hasattr(self, "_using_sb_fixture") and self.__called_setup:
7350+
# This test already called setUp()
7351+
return
7352+
self.__called_setup = True
7353+
self.__called_teardown = False
73397354
self.masterqa_mode = masterqa_mode
73407355
self.is_pytest = None
73417356
try:
@@ -7642,6 +7657,9 @@ def setUp(self, masterqa_mode=False):
76427657
# Although the pytest clock starts before setUp() begins,
76437658
# the time-limit clock starts at the end of the setUp() method.
76447659
sb_config.start_time_ms = int(time.time() * 1000.0)
7660+
if not self.__start_time_ms:
7661+
# Call this once in case of multiple setUp() calls in the same test
7662+
self.__start_time_ms = sb_config.start_time_ms
76457663

76467664
def __set_last_page_screenshot(self):
76477665
""" self.__last_page_screenshot is only for pytest html report logs
@@ -7906,7 +7924,7 @@ def __process_dashboard(self, has_exception, init=False):
79067924
test_id = self.__get_test_id_2()
79077925
dud = "seleniumbase/plugins/pytest_plugin.py::BaseClass::base_method"
79087926
if not init:
7909-
duration_ms = int(time.time() * 1000) - sb_config.start_time_ms
7927+
duration_ms = int(time.time() * 1000) - self.__start_time_ms
79107928
duration = float(duration_ms) / 1000.0
79117929
sb_config._duration[test_id] = duration
79127930
if test_id not in sb_config._display_id.keys():
@@ -7927,27 +7945,53 @@ def __process_dashboard(self, has_exception, init=False):
79277945
sb_config._results.pop(alt_test_id)
79287946
if test_id in sb_config._results.keys() and (
79297947
sb_config._results[test_id] == "Skipped"):
7948+
if self.__passed_then_skipped:
7949+
# Multiple calls of setUp() and tearDown() in the same test
7950+
sb_config.item_count_passed -= 1
7951+
sb_config.item_count_untested += 1
7952+
self.__passed_then_skipped = False
7953+
sb_config._results[test_id] = "Skipped"
79307954
sb_config.item_count_skipped += 1
79317955
sb_config.item_count_untested -= 1
7932-
sb_config._results[test_id] = "Skipped"
79337956
elif self._multithreaded and test_id in existing_res.keys() and (
79347957
existing_res[test_id] == "Skipped"):
7958+
sb_config._results[test_id] = "Skipped"
79357959
sb_config.item_count_skipped += 1
79367960
sb_config.item_count_untested -= 1
7937-
sb_config._results[test_id] = "Skipped"
79387961
elif has_exception:
7939-
# pytest-rerunfailures may cause duplicate results
7940-
if test_id not in sb_config._results.keys() or (
7941-
(not sb_config._results[test_id] == "Failed")):
7962+
if test_id not in sb_config._results.keys():
79427963
sb_config._results[test_id] = "Failed"
79437964
sb_config.item_count_failed += 1
79447965
sb_config.item_count_untested -= 1
7966+
elif not sb_config._results[test_id] == "Failed":
7967+
# tearDown() was called more than once in the test
7968+
if sb_config._results[test_id] == "Passed":
7969+
# Passed earlier, but last run failed
7970+
sb_config._results[test_id] = "Failed"
7971+
sb_config.item_count_failed += 1
7972+
sb_config.item_count_passed -= 1
7973+
else:
7974+
sb_config._results[test_id] = "Failed"
7975+
sb_config.item_count_failed += 1
7976+
sb_config.item_count_untested -= 1
7977+
else:
7978+
# pytest-rerunfailures caused a duplicate failure
7979+
sb_config._results[test_id] = "Failed"
79457980
else:
7946-
if test_id in sb_config._results.keys() and (
7947-
sb_config._results[test_id] == "Failed"):
7948-
# Possibly pytest-rerunfailures reran the test
7981+
if (
7982+
test_id in sb_config._results.keys()
7983+
and sb_config._results[test_id] == "Failed"
7984+
):
7985+
# pytest-rerunfailures reran a test that failed
79497986
sb_config.item_count_failed -= 1
79507987
sb_config.item_count_untested += 1
7988+
elif (
7989+
test_id in sb_config._results.keys()
7990+
and sb_config._results[test_id] == "Passed"
7991+
):
7992+
# tearDown() was called more than once in the test
7993+
sb_config.item_count_passed -= 1
7994+
sb_config.item_count_untested += 1
79517995
sb_config._results[test_id] = "Passed"
79527996
sb_config.item_count_passed += 1
79537997
sb_config.item_count_untested -= 1
@@ -8143,17 +8187,23 @@ def tearDown(self):
81438187
You'll need to add the following line to the subclass's tearDown():
81448188
super(SubClassOfBaseCase, self).tearDown()
81458189
"""
8190+
if not hasattr(self, "_using_sb_fixture") and self.__called_teardown:
8191+
# This test already called tearDown()
8192+
return
8193+
self.__called_teardown = True
8194+
self.__called_setup = False
81468195
try:
81478196
is_pytest = self.is_pytest # This fails if overriding setUp()
81488197
if is_pytest:
81498198
with_selenium = self.with_selenium
81508199
except Exception:
8151-
sub_class_name = str(
8152-
self.__class__.__bases__[0]).split('.')[-1].split("'")[0]
8153-
sub_file_name = str(self.__class__.__bases__[0]).split('.')[-2]
8200+
sub_class_name = (
8201+
str(self.__class__.__bases__[0]).split(".")[-1].split("'")[0]
8202+
)
8203+
sub_file_name = str(self.__class__.__bases__[0]).split(".")[-2]
81548204
sub_file_name = sub_file_name + ".py"
8155-
class_name = str(self.__class__).split('.')[-1].split("'")[0]
8156-
file_name = str(self.__class__).split('.')[-2] + ".py"
8205+
class_name = str(self.__class__).split(".")[-1].split("'")[0]
8206+
file_name = str(self.__class__).split(".")[-2] + ".py"
81578207
class_name_used = sub_class_name
81588208
file_name_used = sub_file_name
81598209
if sub_class_name == "BaseCase":
@@ -8187,7 +8237,8 @@ def tearDown(self):
81878237
print(
81888238
"\nWhen using self.deferred_assert_*() methods in your tests, "
81898239
"remember to call self.process_deferred_asserts() afterwards. "
8190-
"Now calling in tearDown()...\nFailures Detected:")
8240+
"Now calling in tearDown()...\nFailures Detected:"
8241+
)
81918242
if not has_exception:
81928243
self.process_deferred_asserts()
81938244
else:
@@ -8200,8 +8251,11 @@ def tearDown(self):
82008251
if has_exception:
82018252
self.__add_pytest_html_extra()
82028253
sb_config._has_exception = True
8203-
if self.with_testing_base and not has_exception and (
8204-
self.save_screenshot_after_test):
8254+
if (
8255+
self.with_testing_base
8256+
and not has_exception
8257+
and self.save_screenshot_after_test
8258+
):
82058259
test_logpath = self.log_path + "/" + test_id
82068260
self.__create_log_path_as_needed(test_logpath)
82078261
if not self.__last_page_screenshot_png:
@@ -8211,7 +8265,8 @@ def tearDown(self):
82118265
log_helper.log_screenshot(
82128266
test_logpath,
82138267
self.driver,
8214-
self.__last_page_screenshot_png)
8268+
self.__last_page_screenshot_png
8269+
)
82158270
self.__add_pytest_html_extra()
82168271
if self.with_testing_base and has_exception:
82178272
test_logpath = self.log_path + "/" + test_id
@@ -8227,12 +8282,17 @@ def tearDown(self):
82278282
log_helper.log_screenshot(
82288283
test_logpath,
82298284
self.driver,
8230-
self.__last_page_screenshot_png)
8285+
self.__last_page_screenshot_png
8286+
)
82318287
log_helper.log_test_failure_data(
8232-
self, test_logpath, self.driver, self.browser,
8233-
self.__last_page_url)
8288+
self, test_logpath,
8289+
self.driver,
8290+
self.browser,
8291+
self.__last_page_url
8292+
)
82348293
log_helper.log_page_source(
8235-
test_logpath, self.driver, self.__last_page_source)
8294+
test_logpath, self.driver, self.__last_page_source
8295+
)
82368296
else:
82378297
if self.with_screen_shots:
82388298
if not self.__last_page_screenshot_png:
@@ -8242,15 +8302,22 @@ def tearDown(self):
82428302
log_helper.log_screenshot(
82438303
test_logpath,
82448304
self.driver,
8245-
self.__last_page_screenshot_png)
8305+
self.__last_page_screenshot_png
8306+
)
82468307
if self.with_basic_test_info:
82478308
log_helper.log_test_failure_data(
8248-
self, test_logpath, self.driver, self.browser,
8249-
self.__last_page_url)
8309+
self,
8310+
test_logpath,
8311+
self.driver,
8312+
self.browser,
8313+
self.__last_page_url
8314+
)
82508315
if self.with_page_source:
82518316
log_helper.log_page_source(
8252-
test_logpath, self.driver,
8253-
self.__last_page_source)
8317+
test_logpath,
8318+
self.driver,
8319+
self.__last_page_source
8320+
)
82548321
if self.dashboard:
82558322
if self._multithreaded:
82568323
with self.dash_lock:
@@ -8274,15 +8341,19 @@ def tearDown(self):
82748341
else:
82758342
test_id = self.__get_test_id_2()
82768343
if test_id in sb_config._results.keys() and (
8277-
sb_config._results[test_id] == "Skipped"):
8344+
sb_config._results[test_id] == "Skipped"
8345+
):
82788346
self.__insert_test_result(
8279-
constants.State.SKIPPED, False)
8347+
constants.State.SKIPPED, False
8348+
)
82808349
else:
82818350
self.__insert_test_result(
8282-
constants.State.PASSED, False)
8351+
constants.State.PASSED, False
8352+
)
82838353
runtime = int(time.time() * 1000) - self.execution_start_time
82848354
self.testcase_manager.update_execution_data(
8285-
self.execution_guid, runtime)
8355+
self.execution_guid, runtime
8356+
)
82868357
if self.with_s3_logging and has_exception:
82878358
""" If enabled, upload logs to S3 during test exceptions. """
82888359
import uuid
@@ -8292,22 +8363,28 @@ def tearDown(self):
82928363
path = "%s/%s" % (self.log_path, test_id)
82938364
uploaded_files = []
82948365
for logfile in os.listdir(path):
8295-
logfile_name = "%s/%s/%s" % (guid,
8296-
test_id,
8297-
logfile.split(path)[-1])
8298-
s3_bucket.upload_file(logfile_name,
8299-
"%s/%s" % (path, logfile))
8366+
logfile_name = "%s/%s/%s" % (
8367+
guid,
8368+
test_id,
8369+
logfile.split(path)[-1]
8370+
)
8371+
s3_bucket.upload_file(
8372+
logfile_name, "%s/%s" % (path, logfile)
8373+
)
83008374
uploaded_files.append(logfile_name)
83018375
s3_bucket.save_uploaded_file_names(uploaded_files)
83028376
index_file = s3_bucket.upload_index_file(test_id, guid)
83038377
print("\n\n*** Log files uploaded: ***\n%s\n" % index_file)
83048378
logging.info(
8305-
"\n\n*** Log files uploaded: ***\n%s\n" % index_file)
8379+
"\n\n*** Log files uploaded: ***\n%s\n" % index_file
8380+
)
83068381
if self.with_db_reporting:
83078382
from seleniumbase.core.testcase_manager import (
8308-
TestcaseDataPayload)
8383+
TestcaseDataPayload
8384+
)
83098385
from seleniumbase.core.testcase_manager import (
8310-
TestcaseManager)
8386+
TestcaseManager
8387+
)
83118388
self.testcase_manager = TestcaseManager(self.database_env)
83128389
data_payload = TestcaseDataPayload()
83138390
data_payload.guid = self.testcase_guid
@@ -8320,8 +8397,12 @@ def tearDown(self):
83208397
test_logpath = self.log_path + "/" + test_id
83218398
self.__create_log_path_as_needed(test_logpath)
83228399
log_helper.log_test_failure_data(
8323-
self, test_logpath, self.driver, self.browser,
8324-
self.__last_page_url)
8400+
self,
8401+
test_logpath,
8402+
self.driver,
8403+
self.browser,
8404+
self.__last_page_url
8405+
)
83258406
if len(self._drivers_list) > 0:
83268407
if not self.__last_page_screenshot_png:
83278408
self.__set_last_page_screenshot()
@@ -8330,9 +8411,11 @@ def tearDown(self):
83308411
log_helper.log_screenshot(
83318412
test_logpath,
83328413
self.driver,
8333-
self.__last_page_screenshot_png)
8414+
self.__last_page_screenshot_png
8415+
)
83348416
log_helper.log_page_source(
8335-
test_logpath, self.driver, self.__last_page_source)
8417+
test_logpath, self.driver, self.__last_page_source
8418+
)
83368419
elif self.save_screenshot_after_test:
83378420
test_id = self.__get_test_id()
83388421
test_logpath = self.log_path + "/" + test_id
@@ -8342,9 +8425,8 @@ def tearDown(self):
83428425
self.__set_last_page_url()
83438426
self.__set_last_page_source()
83448427
log_helper.log_screenshot(
8345-
test_logpath,
8346-
self.driver,
8347-
self.__last_page_screenshot_png)
8428+
test_logpath, self.driver, self.__last_page_screenshot_png
8429+
)
83488430
if self.report_on:
83498431
self._last_page_screenshot = self.__last_page_screenshot_png
83508432
try:

0 commit comments

Comments
 (0)