コード例 #1
0
    def test_search_bd(self):
        """ 测试搜索'百度'(错误)  """
        log.info("user(test_search_bd): " + self.user)
        log.info("passwd(test_search_bd): " + self.passwd)

        search_page = SearchPage(self)
        search_page.search_bd("百度")
コード例 #2
0
    def test_search_wx(self):
        """ 测试搜索'微信'(失败)  """
        log.info("user(test_search_wx): " + self.user)
        log.info("passwd(test_search_wx): " + self.passwd)

        search_page = SearchPage(self)
        search_page.search_wx("微信")
コード例 #3
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")
コード例 #4
0
    def test_search_hszz(self):
        """ 测试搜索'皇室战争'(通过)  """
        log.info("user(test_search_hszz): " + self.user)
        log.info("passwd(test_search_hszz): " + self.passwd)

        # 根据不同用例特定自定义设置(也可以不设置)
        # self.driver.implicitly_wait(5)

        # 通过Base类调用实例方法 :self(测试用例实例对象)
        Base.screenshot(self, "home.png")

        search_page = SearchPage(self)
        search_page.search_hszz("皇室战争")
コード例 #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 new_run(self, result, debug=False):
    """
    :param self: 表示'suit'实例对象
    :param result: 测试结果报告
    :param debug:
    :return:

     动态修改'suite.py'文件中'TestSuite'类中的'run'方法
      1.为实例对象'suite'<TestSuite>动态修改实例方法'run'
      2.目的:启用多线程来执行case
    """
    topLevel = False
    if getattr(result, '_testRunEntered', False) is False:
        result._testRunEntered = topLevel = True

    # 多线程执行测试
    pool = ThreadPoolExecutor(self.thread_num)
    for index, test in enumerate(self):
        if result.shouldStop:
            break

        if _isnotsuite(test):
            self._tearDownPreviousClass(test, result)
            self._handleModuleFixture(test, result)
            self._handleClassSetUp(test, result)
            result._previousTestClass = test.__class__

            if (getattr(test.__class__, '_classSetupFailed', False) or
                    getattr(result, '_moduleSetUpFailed', False)):
                continue

        """ 启用多线程 调用方法 """
        pool.submit(run_test_custom, self, test, result, debug, index).add_done_callback(show_result_custom)

    """ 等待所有线程执行完毕 """
    pool.shutdown()

    log.info("线程全部执行完毕")

    if topLevel:
        self._tearDownPreviousClass(None, result)
        self._handleModuleTearDown(result)
        result._testRunEntered = False
    return result
コード例 #7
0
 def del_file_by_date(self, date_str):
     """
     删除指定日期之前的所有图片
     :param date_str: 必须是'ISODate'类型的字符串 -> 2020-03-02T15:51:05
     :return:
        {"uploadDate" : {"$lt": ISODate("2020-03-02T15:51:05")}}
     """
     try:
         ISODate = parser.parse(date_str)
         query_dict = {"uploadDate": {"$lt": ISODate}}
         grid_outs = self.fs.find(query_dict)
         file_id_list = []
         for grid_out in grid_outs:
             log.info(grid_out.__dict__)
             file_id_list.append(str(grid_out._file.get("_id")))
         for file_id in file_id_list:
             self.fs.delete(file_id=ObjectId(file_id))
         return len(file_id_list)
     except Exception as e:
         mongo_exception_send_DD(e=e, msg="删除图片")
         return None
コード例 #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 suite_sync_run_case(pro_name, connected_android_device_list=[]):
    """
    同时执行不同用例( 通过动态修改'suite.py'文件中'TestSuite'类中的'run'方法,使得每个线程中的结果都可以记录到测试报告中 )
    :param pro_name: 项目名称
    :param connected_android_device_list: 已连接的设备列表 ( 以 列表数量 作为 线程数量 )
            (1)若 == [] :表示当前是'定时任务'
            (2)若 =! [] :表示当前是'页面执行',并且 已经获取到已连接的Android设备

        【 备 注 】
        1.suite 实例对象(包含了所有的测试用例实例,即继承了'unittest.TestCase'的子类的实例对象 test_instance )
        2.启动 Android 设备中的 APP 应用(每个用例执行一次):在每个'测试类'的 setUp 方法中执行 ( 继承 ParaCase 父类 )
        3.关闭 Android 设备中的 APP 应用 (每个用例执行一次):在每个'测试类'的 tearDown 方法中执行 ( 继承 ParaCase 父类 )

        【 保 存 截 屏 图 片 ID 的 逻 辑 】
        1.为实例对象'suite'<TestSuite>动态添加一个属性'screen_shot_id_dict' -> screen_shot_id_dict = {}
        2.每个测试方法中将所有截屏ID都保存入'screen_shot_id_list' -> screen_shot_id_dict = ['aaa', 'bbb', 'ccc']
        3.实例对象'suite'在重写的'new_run'方法中 将'screen_shot_id_list'添加入'screen_shot_id_dict'
        4.screen_shot_id_dict = { "测试类名.测试方法名":['aaa', 'bbb'], "测试类名.测试方法名":['cccc'] }

        【 并 发 线 程 数 逻 辑 】
        1.通过 adb 命令 查看 Android 设备 连接情况 ( 已连接 | 未连接 | 未授权 )
        2.将'已连接'的设备列表数量 作为 并发线程数量
         [ { "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"} } ]

        【 每 个 用 例 使 用 Android 设 备 逻 辑 】
        通过'当前线程名索引' 获取已连接设备列表中对应的'Android'设备信息

    """

    if is_null(connected_android_device_list):  # 表示当前是'定时任务'

        # (定时任务)需要判断 是否存在运行中的用例
        if is_exist_start_case(pro_name):
            send_DD_for_FXC(title=pro_name,
                            text="#### '" + pro_name +
                            "' 项目存在<运行中>的用例而未执行测试(定时任务)")
            return "Done"

        # (定时任务)需要获取 已连接的 Android 设备信息列表
        connected_android_device_list = get_connected_android_devices_info(
            pro_name)
        if len(connected_android_device_list) == 0:
            send_DD_for_FXC(title=pro_name,
                            text="#### '" + pro_name + "' 项目 未连接任何 Android 设备")
            return "Done"

    # '已连接设备的' 列表数量 作为 线程数量
    log.info("线程数量 : " + str(len(connected_android_device_list)))
    log.info("已连接的Android设备信息列表:" + str(connected_android_device_list) + "\n")

    # 将'测试类'中的所有'测试方法'添加到 suite 对象中(每个'测试类'实例对象包含一个'测试方法')
    from TestBase.test_case_unit import ParaCase
    suite, on_line_test_method_name_list = ParaCase.get_online_case_to_suite(
        pro_name, connected_android_device_list)

    if suite != "mongo error":
        if is_null(on_line_test_method_name_list):
            send_DD_for_FXC(title=pro_name,
                            text="#### '" + pro_name +
                            "' 项目<没有上线>的用例而未执行测试(定时任务)")
        else:
            # 为实例对象'suite'<TestSuite>动态添加一个属性'screen_shot_id_dict'(目的:保存截图ID)
            setattr(suite, "screen_shot_id_dict", {})

            # 为实例对象'suite'<TestSuite>动态添加一个属性'android_device_name_dict'(目的:保存使用的Android设备名称)
            setattr(suite, "android_device_name_dict", {})

            # 为实例对象'suite'<TestSuite>动态添加一个属性'thread_num'(目的:控制多线程数量)
            setattr(suite, "thread_num", len(connected_android_device_list))

            # 为实例对象'suite'<TestSuite>动态添加两个方法'run_test_custom'、'show_result_custom'( 目的:供多线程中调用 )
            suite.run_test_custom = MethodType(run_test_custom, suite)
            suite.show_result_custom = MethodType(show_result_custom, suite)

            # 为实例对象'suite'<TestSuite>动态修改实例方法'run'( 目的:启用多线程来执行case )
            suite.run = MethodType(new_run, suite)

            # 运行测试,并生成测试报告
            test_result, current_report_file = generate_report(
                pro_name=pro_name,
                suite=suite,
                title='Android自动化测试报告 - ' + pro_name,
                description='详细测试用例结果',
                tester="自动化测试",
                verbosity=2)
コード例 #10
0
def suite_sync_run_case(pro_name):
    """
    同时执行不同用例( 通过动态修改'suite.py'文件中'TestSuite'类中的'run'方法,使得每个线程中的结果都可以记录到测试报告中 )
    :param pro_name: 项目名称

        【 备 注 】
        1.suite 实例对象(包含了所有的测试用例实例,即继承了'unittest.TestCase'的子类的实例对象 test_instance )
        2.启动 Android 设备中的 APP 应用(每个用例执行一次):在每个'测试类'的 setUp 方法中执行 ( 继承 ParaCase 父类 )
        3.关闭 Android 设备中的 APP 应用 (每个用例执行一次):在每个'测试类'的 tearDown 方法中执行 ( 继承 ParaCase 父类 )

        【 保 存 截 屏 图 片 ID 的 逻 辑 】
        1.为实例对象'suite'<TestSuite>动态添加一个属性'screen_shot_id_dict' -> screen_shot_id_dict = {}
        2.每个测试方法中将所有截屏ID都保存入'screen_shot_id_list' -> screen_shot_id_dict = ['aaa', 'bbb', 'ccc']
        3.实例对象'suite'在重写的'new_run'方法中 将'screen_shot_id_list'添加入'screen_shot_id_dict'
        4.screen_shot_id_dict = { "测试类名.测试方法名":['aaa', 'bbb'], "测试类名.测试方法名":['cccc'] }

        【 并 发 线 程 数 逻 辑 】
        前提:需要先手动检查: Appium服务是否正常启动、Android设备是否正确连接
        1.获取已连接设备信息列表
         [ { "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" } } ]
        2.返回的列表数量 作为 线程数量

        【 每 个 用 例 使 用 Android 设 备 逻 辑 】
        通过'当前线程名索引' 获取已连接设备列表中对应的'Android'设备信息和'Appium'服务

    """
    # (定时任务)需要判断 是否存在运行中的用例
    if is_exist_start_case(pro_name):
        send_DD_for_FXC(title=pro_name, text="#### '" + pro_name + "' 项目存在<运行中>的用例而未执行测试(定时任务)")
        return "Done"

    # 获取 已连接的 Android 设备信息列表
    connected_android_device_list = config_android_device_with_appium_server_list()
    # 列表数量 作为 线程数量
    thread_num = len(connected_android_device_list)
    log.info("\n线程数量 : " + str(thread_num))
    log.info("已连接的Android设备信息列表:" + str(connected_android_device_list) + "\n")

    if thread_num == 0:
        send_DD_for_FXC(title=pro_name, text="#### '" + pro_name + "' 项目 未连接任何 Android 设备")
        return "Done"

    # 将'测试类'中的所有'测试方法'添加到 suite 对象中(每个'测试类'实例对象包含一个'测试方法')
    from TestBase.test_case_unit import ParaCase
    suite, on_line_test_method_name_list = ParaCase.get_online_case_to_suite(pro_name, connected_android_device_list)

    if suite != "mongo error":
        if is_null(on_line_test_method_name_list):
            send_DD_for_FXC(title=pro_name, text="#### '" + pro_name + "' 项目<没有上线>的用例而未执行测试(定时任务)")
        else:
            # 为实例对象'suite'<TestSuite>动态添加一个属性'screen_shot_id_dict'(目的:保存截图ID)
            setattr(suite, "screen_shot_id_dict", {})

            # 为实例对象'suite'<TestSuite>动态添加一个属性'android_device_name_dict'(目的:保存使用的Android设备名称)
            setattr(suite, "android_device_name_dict", {})

            # 为实例对象'suite'<TestSuite>动态添加一个属性'thread_num'(目的:控制多线程数量)
            setattr(suite, "thread_num", thread_num)

            # 为实例对象'suite'<TestSuite>动态添加两个方法'run_test_custom'、'show_result_custom'( 目的:供多线程中调用 )
            suite.run_test_custom = MethodType(run_test_custom, suite)
            suite.show_result_custom = MethodType(show_result_custom, suite)

            # 为实例对象'suite'<TestSuite>动态修改实例方法'run'( 目的:启用多线程来执行case )
            suite.run = MethodType(new_run, suite)

            # 运行测试,并生成测试报告
            test_result, current_report_file = generate_report(pro_name=pro_name, suite=suite, title='Android自动化测试报告 - ' + pro_name,
                                                               description='详细测试用例结果', tester="自动化测试", verbosity=2)
コード例 #11
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