def teardown_method(self): super().teardown_method() if self.video_config["record"]: video = self._driver.stop_recording_screen() video_folder_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config("project"), "test_reports", "videos") if not os.path.exists(video_folder_path): os.mkdir(video_folder_path) video_file_path = os.path.join( video_folder_path, "%s.mp4" % datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")) with open(video_file_path, "wb") as f: f.write(base64.b64decode(video)) self.log.info("video captured") if self.video_config["only_record_failed"]: stat_file = os.path.join(os.getcwd(), "projects", LoadConfig.load_config("project"), "test_reports", "stat.json") with open(stat_file, "r") as f: current_stat = json.load(f) current_test = os.environ.get('PYTEST_CURRENT_TEST').split( '::') current_test_file = current_test[0].split( os.sep)[-1].split(".")[0] current_test_name = current_test[-1].split(" ")[0] if current_stat["Details"][current_test_file][ current_test_name].lower() == "pass": os.remove(video_file_path) self.log.info("remove video because current test pass")
def start_app(cls): mobile = LoadConfig.load_config()["mobile"] device = LoadConfig.load_config()["device"] project = LoadConfig.load_config()["project"] if device.lower() == "stf": cls.remote_device = StfDevices( LoadConfig.load_config()["env"]["stf_host"]) cls.device_serial = cls.remote_device.get_single_device()["serial"] cls.log.info("device serial: %s" % str(cls.device_serial)) cls.log.info( cls.remote_device.rent_single_device(cls.device_serial).text) cls.remote_connect_url = cls.remote_device.get_user_device_remote_connect_url( cls.device_serial) cls.log.info("connect url: %s" % str(cls.remote_connect_url)) os.system("adb connect " + cls.remote_connect_url) stf_caps = YamlHelper.load_yaml( os.path.join(os.getcwd(), "projects", project, "conf", "device_caps.yaml"))["STF"] device_cap = None for device in stf_caps.values(): if device["deviceName"] == cls.device_serial: device_cap = device break cls._driver = AppiumHelper.get_driver(mobile, device_cap) else: device_cap = YamlHelper.load_yaml( os.path.join(os.getcwd(), "projects", project, "conf", "device_caps.yaml"))[device] cls._driver = AppiumHelper.get_driver(mobile, device_cap)
def browser_home_page(self): if "home_page" in LoadConfig.load_config()["env"].keys(): home_page = LoadConfig.load_config()["env"]["home_page"] self.log.info(f"Go to home page: {home_page}") self.browse_page(home_page) else: self.log.info("no home page value, stay current page")
def start_app(cls): project = LoadConfig.load_config()["project"] executable = LoadConfig.load_config()["env"]["executable"] win_caps_file = os.path.join(os.getcwd(), "projects", project, "conf", "win_caps.yaml") if os.path.exists(win_caps_file): win_caps = YamlHelper.load_yaml(win_caps_file) cls._driver = WinautoHelper.get_driver(executable, win_caps) else: cls._driver = WinautoHelper.get_driver(executable)
def setup_method(self): super().setup_method() self.video_config = LoadConfig.load_config("video") if self.video_config["record"]: video_folder_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config("project"), "test_reports", "videos") if not os.path.exists(video_folder_path): os.mkdir(video_folder_path) self.video_file_path = os.path.join(video_folder_path, "%s.mp4" % datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")) self.vh = VideoHelper(out_file=self.video_file_path) self.vh.start_recording_screen()
def initialize_logger(cls, logger): logging.basicConfig(level=LoadConfig.load_config()["log_level"], format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", filename=os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "log", "AutoTest.log"), filemode='a') if len(logger.handlers) == 0: cls.add_handler(logger, cls.get_handler(level=LoadConfig.load_config()["log_level"])) else: logger.setLevel(LoadConfig.load_config()["log_level"]) return logger
def click(self, locator, *args): by, value = self.format_locator(locator, *args) self.log.info("Click the element found by %s: %s" % (by, value)) if by != "image": try: element = self.wait_until_element_to_be_clickable( locator, *args) except: element = self.find_element(locator, *args) element.click() else: test_data_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data") screenshot_path = os.path.join(test_data_path, "screenshot.png") element_img_path = os.path.join(test_data_path, value) self._driver.save_screenshot(screenshot_path) time.sleep(1) if os.path.exists(screenshot_path): scale_x, scale_y = CVHelper.flann_generate_matched_points_center( element_img_path, screenshot_path) window_size = self._driver.get_window_size() x = round(scale_x * window_size["width"], 2) y = round(scale_y * window_size["height"], 2) self.log.info(f"click on the coordinates: {x}, {y}") self._driver.tap([(x, y)]) else: self.log.info("unable to find the screenshot file")
def click(self, locator, *args): by, value = self.format_locator(locator, *args) self.log.info("Click the element found by %s: %s" % (by, value)) if by != "image": try: element = self.wait_until_element_to_be_clickable(locator, *args) # element.location_once_scrolled_into_view self.scroll_into_view_of_element(element) except: element = self.find_element(locator, *args) element.click() else: test_data_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data") screenshot_path = os.path.join(test_data_path, "screenshot.png") element_img_path = os.path.join(test_data_path, value) self._driver.save_screenshot(screenshot_path) time.sleep(1) if os.path.exists(screenshot_path): scale_x, scale_y = CVHelper.flann_generate_matched_points_center(element_img_path, screenshot_path) window_size = self._driver.get_window_size() x = round(scale_x * window_size["width"], 2) y = round(scale_y * window_size["height"], 2) self.log.info(f"click on the coordinates: {x}, {y}") whole_page = self.find_element({"by": "xpath", "value": "//html/body"}) ActionChains(self._driver).move_to_element_with_offset(whole_page, 1, 1).perform() ActionChains(self._driver).move_by_offset(x, y).click().perform() else: self.log.info("unable to find the screenshot file")
def __init__(self, api_name): self.api_name = api_name self.current_class = os.environ.get('PYTEST_CURRENT_TEST').split('::')[-2].split(' ')[0] self.log = logging.getLogger(self.current_class) self.config = LoadConfig.load_config() self.url = "/".join([self.config["env"]["base_url"], self.config["env"]["api_list"][self.api_name]]) self.new_url = None
def teardown_class(cls): super().teardown_class() AppiumHelper.close_driver() device = LoadConfig.load_config()["device"] if device.lower() == "stf": os.system("adb disconnect " + cls.remote_connect_url) cls.log.info( cls.remote_device.return_rented_device(cls.device_serial).text)
def flann_generate_matched_points_center(cls, target, source="screenshot.png"): base_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data") img_target = cv2.imread(os.path.join(base_path, target), 0) img_source = cv2.imread(os.path.join(base_path, source), 0) print('target image size: height, width: {}, {}'.format(img_target.shape[0], img_target.shape[1])) print('source image size: height, width: {}, {}'.format(img_source.shape[0], img_source.shape[1])) sift = cv2.xfeatures2d.SIFT_create() kp1, des1 = sift.detectAndCompute(img_target, None) kp2, des2 = sift.detectAndCompute(img_source, None) FLANN_INDEX_KDTREE = 0 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matches = flann.knnMatch(des1, des2, k=2) points = [] for m, n in matches: if m.distance < 0.75 * n.distance: points.append(m) h1, w1 = img_target.shape[:2] h2, w2 = img_source.shape[:2] view = np.zeros((max(h1, h2), w1 + w2, 3), np.uint8) view[:h1, :w1, 0] = img_target view[:h2, w1:, 0] = img_source view[:, :, 1] = view[:, :, 0] view[:, :, 2] = view[:, :, 0] coordinate_x = [] coordinate_y = [] for p in points: coordinate_x.append(int(kp2[p.trainIdx].pt[0])) coordinate_y.append(int(kp2[p.trainIdx].pt[1])) scale_x = round(sum(coordinate_x) / len(points) / img_source.shape[1], 2) scale_y = round(sum(coordinate_y) / len(points) / img_source.shape[0], 2) return scale_x, scale_y # temp = [] # for m, n in matches: # if m.distance < 0.6 * n.distance: # temp.append(m) # src_pts = np.float32([kp1[m.queryIdx].pt for m in temp]).reshape(-1, 1, 2) # dst_pts = np.float32([kp2[m.trainIdx].pt for m in temp]).reshape(-1, 1, 2) # M, mask = cv2.findHomography(src_pts, dst_pts, cv2.LMEDS, 5.0) # matches_mask = mask.ravel().tolist() # # h, w = img_target.shape # pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2) # # dst = cv2.perspectiveTransform(pts, M) # img_source_new = cv2.polylines(img_source, [np.int32(dst)], True, 255, 3, cv2.LINE_AA) # # area = [np.int32(dst)] # # # compute object center coordinate in the search image # x = (area[0][2][0][0] - area[0][0][0][0]) / 2 + area[0][0][0][0] # y = (area[0][1][0][1] - area[0][0][0][1]) / 2 + area[0][0][0][1] # return x, y
def __init__(self, driver, logger): self._driver = driver self.log = logger self._config = LoadConfig.load_config() self.behavior = self.__init_behavior_by_project_type() element_file = os.path.join(os.getcwd(), "projects", self._config["project"], "pages", "elements", "%s.yaml" % self.__module__.split(".")[-1]) if os.path.exists(element_file): self._elements = YamlHelper.load_yaml(element_file) else: self.log.critical("no element definition file found!!: %s" % element_file)
def start_browser(cls): browser = LoadConfig.load_config()["browser"] if browser.lower() in ["chrome", "firefox", "ie", "edge", "safari"]: cls.log.info("Start to launch browser - %s" % browser) cls._driver = SeleniumHelper.get_driver(browser) else: device = LoadConfig.load_config()["device"] cls.log.info("Start to launch browser - %s with device name %s" % (browser, device)) cls._driver = SeleniumHelper.get_driver(browser, device_name=device) try: if browser.lower() == "chrome": width, height = cls._driver.execute_script("return [window.screen.availWidth, window.screen.availHeight];") cls.log.info(f"set window size to width: {width} and height: {height}") cls._driver.set_window_size(width, height) else: cls.log.info("maximize browser window") cls._driver.maximize_window() except WebDriverException as e: cls.log.warning("fail to set window size: %s" % str(e))
def input_texts_into_edit_then_save(self, texts, file_name): self.log.info("Input texts into edit area") self.element("edit_input").input_value(texts) main_window = self.element_info("main_window") self.behavior.select_menu(main_window, ["File", "Save As..."]) file_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data", file_name) self.element("save_file_input").input_value(file_path) self.element("save_button").click()
def teardown_method(self): super().teardown_method() if self.video_config["record"]: self.vh.stop_recording_screen() self.log.info("video captured") if self.video_config["only_record_failed"]: stat_file = os.path.join(os.getcwd(), "projects", LoadConfig.load_config("project"), "test_reports", "stat.json") with open(stat_file, "r") as f: current_stat = json.load(f) current_test = os.environ.get('PYTEST_CURRENT_TEST').split('::') current_test_file = current_test[0].split("/")[-1].split(".")[0] current_test_name = current_test[-1].split(" ")[0] if current_stat["Details"][current_test_file][current_test_name].lower() == "pass": os.remove(self.video_file_path) self.log.info("remove video because current test pass")
def sift_show_points_matched(cls, target, source="screenshot.png"): base_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data") img_target = cv2.imread(os.path.join(base_path, target), 0) img_source = cv2.imread(os.path.join(base_path, source), 0) print('target image size: height, width: {}, {}'.format(img_target.shape[0], img_target.shape[1])) print('source image size: height, width: {}, {}'.format(img_source.shape[0], img_source.shape[1])) sift = cv2.xfeatures2d.SIFT_create() kp1, des1 = sift.detectAndCompute(img_target, None) kp2, des2 = sift.detectAndCompute(img_source, None) bf = cv2.BFMatcher() points = [] matches = bf.knnMatch(des1, des2, k=2) for m, n in matches: if m.distance < 0.75 * n.distance: points.append([m]) img_result = cv2.drawMatchesKnn(img_target, kp1, img_source, kp2, points, None, flags=2) plt.imshow(img_result) plt.show()
def click(self, locator, *args): by, value = self.format_locator(locator, *args) self.log.info("Click the element found by %s: %s" % (by, value)) if by != "image": element = self.wait_until_element_to_be_clickable(locator, *args) element.click() else: test_data_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data") screenshot_path = os.path.join(test_data_path, "screenshot.png") element_img_path = os.path.join(test_data_path, value) width, height = Win32Helper.capture_screen(screenshot_path) time.sleep(1) if os.path.exists(screenshot_path): scale_x, scale_y = CVHelper.flann_generate_matched_points_center(element_img_path, screenshot_path) x = round(scale_x * width, 2) y = round(scale_y * height, 2) self.log.info(f"click on the coordinates: {x}, {y}") Mouse.click("left", (x, y)) else: self.log.info("unable to find the screenshot file")
def swipe(self, direction, duration=1000): self.log.info("Swipe to direction: %s" % direction) if LoadConfig.load_config()["device"].lower().startswith("ip"): self._driver.execute_script("mobile: swipe", {"direction": direction}) else: screen_size = self._driver.get_window_size() directions = { "up": { "start_x": screen_size.width / 2, "start_y": screen_size.height * 3 / 4, "end_x": screen_size.width / 2, "end_y": screen_size.height / 4, duration: duration }, "down": { "start_x": screen_size.width / 2, "start_y": screen_size.height / 4, "end_x": screen_size.width / 2, "end_y": screen_size.height * 3 / 4, duration: duration }, "left": { "start_x": screen_size.width * 4 / 5, "start_y": screen_size.height / 2, "end_x": screen_size.width / 5, "end_y": screen_size.height / 2, duration: duration }, "right": { "start_x": screen_size.width / 5, "start_y": screen_size.height / 2, "end_x": screen_size.width * 4 / 5, "end_y": screen_size.height / 2, duration: duration } } self._driver.swipe(directions[direction]["start_x"], directions[direction]["start_y"], directions[direction]["end_x"], directions[direction]["end_y"], duration)
class TestSample(LoggedTestCase): def test_answer1(self): """TEMP-1: this is description of test answer1""" assert 2 + 3 == 5 @pytest.mark.error def test_answer2(self): """TEMP-2: this is description of test answer2""" assert 2 + 4 == 5 @pytest.mark.sample @pytest.mark.temp def test_answer3(self): """TEMP-3: this is description of test answer3""" assert 2 + 3 == 5 @pytest.mark.skipif(LoadConfig.load_config()["tag"].lower() in ["staging", "prod", "all"], reason="not ready") def test_answer4(self): """TEMP-4: this is description of test answer4""" assert 2 + 4 == 5
def pytest_configure(config): if hasattr(config, '_metadata'): run_config_data = LoadConfig.load_config() if "Python" in config._metadata.keys(): del config._metadata["Python"] if "Packages" in config._metadata.keys(): del config._metadata["Packages"] if "Plugins" in config._metadata.keys(): del config._metadata["Plugins"] if "JAVA_HOME" in config._metadata.keys(): del config._metadata["JAVA_HOME"] config._metadata["Project"] = run_config_data["project"] config._metadata["Environment"] = run_config_data["environment"] if run_config_data["report"]["ui_test"]: if run_config_data["report"]["app_test"]: config._metadata["Mobile"] = run_config_data["mobile"] config._metadata["Device"] = run_config_data["device"] elif run_config_data["report"]["win_test"]: config._metadata["Type"] = "Windows Software" else: config._metadata["Browser"] = run_config_data["browser"] else: config._metadata["Type"] = "API"
def get_project_config_data(): return LoadConfig.load_config()["env"]
def go_to_home_page(self): home_page = LoadConfig.load_config()["env"]["home_page"] self.log.info(f"Go to home page: {home_page}") self.behavior.go_to_page(home_page) self.element("search_button").wait_clickable()
def setup_method(self): super().setup_method() self.video_config = LoadConfig.load_config("video") if self.video_config["record"]: self._driver.start_recording_screen()
def __init__(self): self.env_config = LoadConfig.load_config()["env"]
def notepad_is_able_to_save_content_to_file(self, file_name): file_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data", file_name) assert self.check_file_exists_in_test_data( file_path), "not find the file: %s" % str(file_path)
def remove_file_if_exists_in_test_data(self, file_name): file_path = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_data", file_name) if self.check_file_exists_in_test_data(file_path): os.remove(file_path)
def _load_config(self): self._config = LoadConfig.load_config()
def pytest_runtest_makereport(item, call): # stat_file = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_reports", "stat.json") global total_sum global pass_sum global fail_sum global skip_sum global module_case global failures global start_time global browser_name global browser_version global mobile_platform_name global mobile_platform_version outcome = yield rep = outcome.get_result() test_file = item.function.__module__.split(".")[-1] if test_file not in module_case.keys(): module_case[test_file] = {} if test_file not in failures.keys(): failures[test_file] = {} rep.description = str(item.function.__doc__) setattr(item, "rep_" + rep.when, rep) if rep.when == "setup" and rep.skipped: test_method = rep.nodeid.split("::")[-1] if test_method not in module_case[test_file]: total_sum += 1 skip_sum += 1 module_case[test_file][test_method] = "skip" if rep.when == "call": print("%s: Case Duration: %ss ...%s" % (rep.nodeid.split("::")[-1], str(round(rep.duration, 2)), rep.outcome)) config = LoadConfig.load_config() if config["report"]["ui_test"]: if config["report"]["app_test"]: driver = AppiumHelper.get_current_driver() cap = driver.capabilities mobile_platform_name = cap["platformName"] mobile_platform_version = cap["platformVersion"] elif not config["report"]["win_test"]: driver = SeleniumHelper.get_current_driver() cap = driver.capabilities browser_name = cap["browserName"] browser_version = cap["browserVersion"] test_method = rep.nodeid.split("::")[-1] if rep.passed: if test_method not in module_case[test_file]: total_sum += 1 pass_sum += 1 else: pass_sum += 1 fail_sum -= 1 module_case[test_file][test_method] = "pass" if test_method in failures[test_file]: del failures[test_file][test_method] elif rep.failed: if test_method not in module_case[test_file]: total_sum += 1 fail_sum += 1 module_case[test_file][test_method] = "fail" failures[test_file][test_method] = { "error_message": rep.longreprtext } config = LoadConfig.load_config() if config["report"]["ui_test"]: screen_folder_path = os.path.join(os.getcwd(), "projects", config["project"], "test_reports", "screenshots") if not os.path.exists(screen_folder_path): os.mkdir(screen_folder_path) if config["report"]["app_test"]: driver = AppiumHelper.get_current_driver() elif not config["report"]["win_test"]: driver = SeleniumHelper.get_current_driver() screenshot_file_path = os.path.join( screen_folder_path, "%s.png" % datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")) if config["report"]["win_test"]: from utils.win32_helper import Win32Helper Win32Helper.capture_screen(screenshot_file_path) else: driver.save_screenshot(screenshot_file_path) failures[test_file][test_method][ "screenshot"] = screenshot_file_path.split(os.getcwd())[-1] html = '<div><img src="%s" alt="screenshot" style="width:304px;height:228px;" ' \ 'onclick="window.open(this.src)" align="right"/></div>' % screenshot_file_path extra = getattr(rep, 'extra', []) extra.append( item.config.pluginmanager.getplugin('html').extras.html( html)) rep.extra = extra elif rep.skipped: total_sum += 1 skip_sum += 1 module_case[test_file][test_method] = "skip" print("Run %d cases, Current Status: Pass - %d, Fail - %d, Skip - %d" % (total_sum, pass_sum, fail_sum, skip_sum))
def pytest_sessionfinish(session, exitstatus): global start_time global browser_name global browser_version global mobile_platform_name global mobile_platform_version global failures stat_file = os.path.join(os.getcwd(), "projects", LoadConfig.load_config()["project"], "test_reports", "stat.json") session_pass_sum = session_fail_sum = session_skip_sum = 0 session_module_case = {} session_case_names = {} session_class_doc = {} reporter = session.config.pluginmanager.get_plugin('terminalreporter') expect_types = ["passed", "failed", "skipped"] alias = {"passed": "pass", "failed": "fail", "skipped": "skip"} actual_types = reporter.stats.keys() for rt in expect_types: if rt in actual_types: for item in reporter.stats[rt]: test_file = item.nodeid.split("tests/")[-1].split( "::")[0].split(".")[0] test_file_path, test_class_name, _ = item.nodeid.split("::") if test_class_name not in session_class_doc.keys(): with open(os.path.join(os.getcwd(), test_file_path)) as fd: tree = ast.parse(fd.read()) for node in ast.walk(tree): if isinstance(node, ast.ClassDef ) and node.name == test_class_name: docstring = ast.get_docstring(node) session_class_doc[test_file] = yaml.load( docstring, Loader=yaml.BaseLoader) test_method = item.nodeid.split("::")[-1] test_result = item.outcome test_case_name = item.description unique_test_method = test_method.split("[")[0] if test_result == "passed": session_pass_sum += 1 elif test_result == "failed": session_fail_sum += 1 elif test_result == "skipped": session_skip_sum += 1 if test_file not in session_module_case.keys(): session_module_case[test_file] = { test_method: alias[test_result] } session_case_names[test_file] = { unique_test_method: test_case_name } else: session_module_case[test_file][test_method] = alias[ test_result] if unique_test_method not in session_case_names[test_file]: session_case_names[test_file][ unique_test_method] = test_case_name session_total_sum = session_pass_sum + session_fail_sum + session_skip_sum current_result = { "Total": session_total_sum, "Pass": session_pass_sum, "Fail": session_fail_sum, "Skip": session_skip_sum, "Start_Time": start_time, "End_Time": datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S.%f"), "Brief": session_class_doc, "Details": session_module_case, "Cases": session_case_names, "Failures": failures } config = LoadConfig.load_config() if config["report"]["ui_test"]: if config["report"]["app_test"]: current_result["mobile_platform_name"] = mobile_platform_name current_result["mobile_platform_version"] = mobile_platform_version elif not config["report"]["win_test"]: current_result["browser_name"] = browser_name current_result["browser_version"] = browser_version with open(stat_file, "w") as f: json.dump(current_result, f)
def run(self): self.start_time = datetime.datetime.now() self._load_config() # print(self._config) report_folder_path = os.path.join(os.getcwd(), "projects", self._config["project"], "test_reports") log_folder_path = os.path.join(os.getcwd(), "projects", self._config["project"], "log") data_folder_path = os.path.join(os.getcwd(), "projects", self._config["project"], "test_data") for folder in [report_folder_path, log_folder_path, data_folder_path]: if not os.path.exists(folder): os.mkdir(folder) if self._config["report"]["ui_test"]: if self._config["report"]["app_test"]: report_suffix = self._config["mobile"] elif self._config["report"]["win_test"]: report_suffix = "WindowsSoftware" else: report_suffix = self._config["browser"] else: report_suffix = "API" report_path = os.path.join( report_folder_path, "AutoTest-%s-%s-%s-%s.html" % (self._config["project"], self._config["environment"], report_suffix, datetime.datetime.now().strftime("%Y%m%d%H%M%S"))) # -v shows the result of each def; -q only shows the overall status; -s shows the print function in test def command_list = [ "--html", report_path, "--self-contained-html", "-v", "--tb=short" ] # if has include_test, then run these cases; else check and run exclude_test if self._config["test"]: for in_test in self._config["test"].split(","): command_list.append( os.path.join("projects", self._config["project"], "tests", in_test.strip())) elif not self._config["test"]: command_list.append( os.path.join("projects", self._config["project"], "tests")) elif self._config["exclude_test"]: for ex_test in self._config["exclude_test"].split(","): command_list.append("--deselect") command_list.append( os.path.join("projects", self._config["project"], "tests", ex_test.strip())) # run tests which name match keyword, example: keyword, not keyword, key1 or key2, key1 and key2 if self._config["keyword"]: command_list.append("-k") command_list.append(self._config["keyword"].strip()) # run tests which name match marker, example: marker, not marker, marker1 or marker2, marker1 and marker2 if self._config["marker"]: command_list.append("-m") command_list.append(self._config["marker"].strip()) # rerun failures if self._config["rerun"]["rerun_times"]: command_list.append("--reruns") command_list.append(str(self._config["rerun"]["rerun_times"])) if self._config["rerun"]["rerun_delay"]: command_list.append("--reruns-delay") command_list.append(str(self._config["rerun"]["rerun_delay"])) # log #command_list.append('--log-format="%(asctime)s %(levelname)s %(message)s"') #command_list.append('--log-date-format="%Y-%m-%d %H:%M:%S"') #command_list.append("--show-capture=no") command_list.append("--log-file=%s" % os.path.join( os.getcwd(), "projects", LoadConfig.load_config()["project"], "log", "AutoTest-%s.log" % datetime.datetime.now().strftime("%Y%m%d%H%M%S"))) # multi-process try: if int(self._config["process"]) > 1: command_list.append("-n") command_list.append(self._config["process"]) except (ValueError, KeyError): pass pytest.main(command_list) # print(command_list) self.exit_test() self.end_time = datetime.datetime.now() result_statistics = self._generate_result_statistics( report_folder_path) if self._config["email_sender"]["send_report"]: self._send_test_result(result_statistics, report_path) print( "Overall Start Time: %s\nOverall End Time: %s\nOverall Duraion: %s\nReport file in: %s" % (str(self.start_time), str(self.end_time), str(self.end_time - self.start_time), report_path))