示例#1
0
    def setUp(self):
        """
        【 每个用例对象执行前,需要进行如下配置 】

        【 备 注 】
            self.driver  : 操作 Android 设备
            self.session : 操作 APP 应用
        :return:
        """
        from Config.pro_config import get_login_accout
        # 通过线程名的索引 获取登录账号
        self.user, self.passwd = get_login_accout(
            self.current_thread_name_index)

        # 获取'Android'驱动、设备名称
        self.driver, self.device_name = get_android_driver(
            self.pro_name, self.current_thread_name_index,
            self.connected_android_device_list)
        # 获取APP应用信息
        from Config.pro_config import get_app_package
        self.app_package = get_app_package(self.pro_name)

        # 通过'Android'驱动 启动APP应用
        try:
            self.session = self.driver.session(self.app_package)
        except Exception as e:
            log.error(("显示异常:" + str(e)))
            if "SessionBrokenError" in str(e):
                error_msg = self.pro_name + " 项目的APP应用没有启动"
            elif "package not found" in str(e):
                error_msg = self.pro_name + " 项目的APP应用package名称有误"
            else:
                error_msg = self.pro_name + " 项目启动APP时 出现异常情况"
            send_DD_for_FXC(title=self.pro_name, text="#### " + error_msg + "")
            raise Exception(error_msg)
示例#2
0
def generate_report(pro_name, suite, title, description, tester, verbosity=1):
    """
    生 成 测 试 报 告
    备注:每次生成的报告都存放在../logs/history/中,同时替换../logs/下的report.html
    :param pro_name:
    :param suite: suite 实例对象(包含了所有的测试用例实例,即继承了'unittest.TestCase'的子类的实例对象 test_instance )
    :param title:
    :param description:
    :param tester:
    :param verbosity: 结果显示的详细程度
    :return:
    """
    print("实例对象suite是否存在'thread_num'属性:" + str(hasattr(suite, "thread_num")))
    print("实例对象suite是否存在'screen_shot_id_dict'属性:" +
          str(hasattr(suite, "screen_shot_id_dict")))
    print("实例对象suite是否存在'run_test_custom'方法:" +
          str(hasattr(suite, "run_test_custom")))
    print("实例对象suite是否存在'show_result_custom'方法:" +
          str(hasattr(suite, "show_result_custom")))
    print("实例对象suite是否存在'run'方法:" + str(hasattr(suite, "run")))
    print(suite)
    print(suite.__class__)
    print(suite.__class__.__base__)
    print("+++++++++++++++++++++++++++++++++++")

    now = time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime(time.time()))
    current_report_name = "[Android_report]" + pro_name + "[" + now + "].html"
    pro_report_path = cfg.REPORTS_DIR + pro_name + "/"
    history_report_path = pro_report_path + "history/"
    mkdir(history_report_path)
    current_report_file = history_report_path + current_report_name
    with open(current_report_file, 'wb') as fp:
        runner = HTMLTestRunner(stream=fp,
                                title=title,
                                description=description,
                                tester=tester,
                                verbosity=verbosity)
        test_result = runner.run(suite)

    # 将最新报告替换../Reports/{{pro_name}}/下的[Android_report]{{pro_name}}.html
    res = os.system("cp " + current_report_file + " " + pro_report_path +
                    " && "
                    "mv " + pro_report_path + current_report_name + " " +
                    pro_report_path + "[Android_report]" + pro_name + ".html")
    if res != 0:
        log.error("测试报告替换操作有误!")

    # log.info(test_result)
    # log.info("执行总数:" + str(test_result.error_count + test_result.success_count + test_result.failure_count))
    # log.info("执行的用例列表:" + str(test_result.result))
    # log.info("错误数:" + str(test_result.error_count))
    # log.info("错误的用例列表:" + str(test_result.errors))
    # log.info("失败数:" + str(test_result.failure_count))
    # log.info("失败的用例列表:" + str(test_result.failures))
    # log.info("成功数:" + str(test_result.success_count))
    # log.info("成功的用例列表:" + str([success[1] for success in test_result.result if success[0] == 0]))
    # log.info(suite.screen_shot_id_dict)
    return test_result, current_report_file
示例#3
0
 def get_page_with_time_out(self, url, time_out):
     try:
         self.driver.set_page_load_timeout(time_out)
         self.driver.get(url)
     except TimeoutException:
         log.error("页面'" + url + "'加载 " + str(time_out) + " 秒超时了!")
         self.driver.execute_script('window.stop()')
     finally:
         self.driver.set_page_load_timeout(gv.PAGE_LOAD_TIME)  # 还原默认的加载页面超时时间
示例#4
0
def clear_screen_shot(days):
    """
    删除指定日期之前的所有的截图
    :param days:
    :return:
    """
    date_str = get_date_by_days(days=days, time_type="%Y-%m-%dT%H:%M:%S")
    mgf = MongoGridFS()
    del_num = mgf.del_file_by_date(date_str)
    if is_null(del_num):
        log.error("\n清理'" + date_str + "'之前的截图时出错了!\n")
    else:
        log.info("\n已清理'" + date_str + "'之前的截图:" + str(del_num) + " 个\n")
示例#5
0
    def db_connection(self):
        db = None
        try:
            if self.replica_set_name:
                # 当pymongo更新到3.x版本, 连接副本集的方法得用MongoClient, 如果版本<=2.8.1的, 得用MongoReplicaSetClient
                db = MongoClient(self.ip, replicaset=self.replica_set_name)
            else:
                db = MongoClient(self.ip, self.port)
            log.info("mongodb connection success")

        except Exception as e:
            log.error("mongodb connection failed: %s" % self.collection)
            print(e)
            print(traceback.format_exc())
        return db
示例#6
0
 def browser_driver():
     try:
         if remote:
             if browser_name == "Firefox":
                 return webdriver.Remote(command_executor='http://' + cfg.GRID_REMOTE_ADDR + '/wd/hub',
                                         desired_capabilities=DesiredCapabilities.FIREFOX)
             if browser_name == "Chrome":
                 return webdriver.Remote(command_executor='http://' + cfg.GRID_REMOTE_ADDR + '/wd/hub',
                                         desired_capabilities=DesiredCapabilities.CHROME)
         else:
             if browser_name == "Firefox":
                 return webdriver.Firefox(service_log_path=None)
             if browser_name == "Chrome":
                 return webdriver.Chrome()
     except Exception as e:
         log.error(("显示异常:" + str(e)))
         log.error("远程浏览器监听未开启!!!")
         raise Exception("远程浏览器监听未开启")
示例#7
0
def run_test_custom(self, test, result, debug, index):
    """
    :param self: 表示'suit'实例对象
    :param test: 表示'测试用例'实例对象
    :param result: 测试结果报告
    :param debug:
    :param index:
    :return:

      多线程中执行的内容
       1.需要为实例对象'suite'<TestSuite>动态添加该方法
       2.目的:供多线程中调用
    """
    # 启动测试用例:设置用例的'运行状态=running'和'开始时间'
    start_case_run_status(pro_name=test.pro_name,
                          test_method_name=test.test_method)

    if not debug:
        test(result)
    else:
        test.debug()

    # (self)实例对象'suite'<TestSuite> 为每个执行完毕的(test)'测试用例'实例 保存'截图ID列表'
    try:
        self.screen_shot_id_dict[
            test.screen_shot_id_list_name] = test.screen_shot_id_list
    except Exception as e:
        send_DD_for_FXC(title=test.pro_name,
                        text="#### 出现异常 - 可能 远程浏览器监听未开启!!!")
        log.error(str(e))

    if self._cleanup:
        self._removeTestAtIndex(index)

    # 停止测试用例:设置用例的'运行状态=stopping'和'运行时间'
    stop_case_run_status(pro_name=test.pro_name,
                         test_method_name=test.test_method)

    # 返回值<'tuple'>:返回测试用例实例对象的两个属性值( 项目名称、测试方法名 )供回调函数使用
    return test.pro_name, test.test_method
示例#8
0
def get_android_driver(pro_name, current_thread_name_index,
                       connected_android_device_list):
    """
    【 获取'Android'驱动、设备名称 】
    :param pro_name
    :param current_thread_name_index: 当前线程名字的索引
    :param connected_android_device_list: 已连接设备信息列表
    [ { "thread_index": 1, "device_name": "小米5S",  "device_udid": "192.168.31.136:5555"} } ,
      { "thread_index": 2, "device_name": "坚果Pro", "device_udid": "192.168.31.253:4444" } } ]
    :return:

    【 步 骤 】
    1.获取 Appium 服务启动应用所需的能力参数 (指定设备,指定应用)
    2.通过'当前线程名索引' 获取已连接设备列表中对应的'Android'设备信息和'Appium'服务
    3.获取设备驱动
    """

    # 通过'当前线程名索引' 获取已连接设备列表中对应的'Android'设备信息和'Appium'服务
    device_name = None
    device_udid = None
    for connected_android_devices_dict in connected_android_device_list:
        if current_thread_name_index == connected_android_devices_dict[
                "thread_index"]:
            device_udid = connected_android_devices_dict["device_udid"]
            device_name = connected_android_devices_dict["device_name"]
            break
    log.info("\n\n")
    log.info("device_name -> " + device_name)
    log.info("device_udid -> " + device_udid)
    log.info("\n\n")

    driver = None
    try:
        # 连接设备 ADB_WIFI
        driver = uiautomator2.connect_adb_wifi(device_udid)

        # 连接设备 WIFI
        # driver = uiautomator2.connect('192.168.31.136')
        # driver = uiautomator2.connect_wifi('192.168.31.136')

        # 连接设备 USB
        # driver = uiautomator2.connect('15a6c95a')
        # driver = uiautomator2.connect_usb('15a6c95a')

        # 配置accessibility服务的最大空闲时间,超时将自动释放
        driver.set_new_command_timeout(gv.NEW_COMMAND_TIMEOUT)

        # 全局默认的元素定位超时时间
        driver.implicitly_wait(gv.IMPLICITY_WAIT)

        # 解锁(点亮屏幕)相当于点击了home健
        driver.unlock()

    except Exception as e:
        log.error(("显示异常:" + str(e)))
        if "Uiautomator started failed" in str(e):
            error_msg = pro_name + " 项目 " + device_name + " 设备 启动 ATX 服务时 未授权"
        else:
            error_msg = pro_name + "项目 " + device_name + " 设备 启动 ATX 服务的其他异常情况"
        send_DD_for_FXC(title=pro_name, text="#### " + error_msg + "")
        raise Exception(error_msg)
    finally:
        return driver, device_name
示例#9
0
def get_android_driver(pro_name, current_thread_name_index, connected_android_device_list):
    """
    【 获取 Android 设备驱动 】
    :param pro_name
    :param current_thread_name_index: 当前线程名字的索引
    :param connected_android_device_list: 已连接设备信息列表
    [ { "thread_index": 1, "device_name": "小米5S", "platform_version": "7.0", "device_udid": "192.168.31.136:5555", "appium_server": "http://127.0.0.1:4724/wd/hub" } } ,
      { "thread_index": 2, "device_name": "坚果Pro", "platform_version": "7.1.1", "device_udid": "192.168.31.253:4444", "appium_server": "http://127.0.0.1:4723/wd/hub" } } ]
    :return:

    【 步 骤 】
    1.获取 Appium 服务启动应用所需的能力参数 (指定设备,指定应用)
    2.通过'当前线程名索引' 获取已连接设备列表中对应的'Android'设备信息和'Appium'服务
    3.获取设备驱动
    """

    # 获取 Appium 服务启动应用所需的能力参数 (指定设备,指定应用)
    from Config.pro_config import get_app_info
    app_info = get_app_info(pro_name)
    desired_caps = dict()
    desired_caps["platformName"] = "Android"
    desired_caps["appPackage"] = app_info["appPackage"]
    desired_caps["appActivity"] = app_info["appActivity"]
    # 使用哪个自动化引擎
    desired_caps["automationName"] = "UiAutomator2"
    # Appium 等待接收从客户端发送的新命令的超时时长,超时后Appium会终止会话
    desired_caps["newCommandTimeout"] = 30
    # Android 等待设备就绪的超时时长,以秒为单位
    desired_caps["deviceReadyTimeout"] = 30
    # Android 在启动后等待设备就绪的超时时长,以秒为单位
    desired_caps["androidDeviceReadyTimeout"] = 30

    # appium 启动时进程保存的原因(有待验证)
    # desired_caps["adbExecTimeout"] = 20000
    # desired_caps["uiautomator2ServerLaunchTimeout"] = 30000

    # 唤醒屏幕(效果不理想)
    desired_caps["unlockType"] = "pattern"
    desired_caps["unlockKey"] = "12589"

    # 通过'当前线程名索引' 获取已连接设备列表中对应的'Android'设备信息和'Appium'服务
    device_name = None
    appium_server = None
    for connected_android_devices_dict in connected_android_device_list:
        if current_thread_name_index == connected_android_devices_dict["thread_index"]:
            desired_caps["platformVersion"] = connected_android_devices_dict["platform_version"]
            desired_caps["deviceName"] = connected_android_devices_dict["device_udid"]
            device_name = connected_android_devices_dict["device_name"]
            appium_server = connected_android_devices_dict["appium_server"]
            break
    log.info("\n\n")
    log.info("device_name -> " + device_name)
    log.info("appium_server -> " + appium_server)
    log.info("\n\n")
    # 获取设备驱动
    try:
        driver = webdriver.Remote(appium_server, desired_caps)
    except Exception as e:
        log.error(("显示异常:" + str(e)))
        if "Failed to establish a new connection" in str(e):
            error_msg = "Appium 服务(" + appium_server + ")未启动"
        elif "Could not find a connected Android device" in str(e):
            error_msg = "Android 设备(" + device_name + ")未连接"
        elif "Failed to launch Appium Settings app" in str(e):
            error_msg = "Appium Setting 应用启动超时"
        else:
            error_msg = "启动 Appium 服务的其他异常情况"
        send_DD_for_FXC(title=pro_name, text="#### " + error_msg + "")
        raise Exception(error_msg)
    return driver, device_name