全网最牛,Appium自动化测试框架-关键字驱动+数据驱动实战(一)

news2024/11/26 14:33:47

目录:导读

    • 前言
    • 一、Python编程入门到精通
    • 二、接口自动化项目实战
    • 三、Web自动化项目实战
    • 四、App自动化项目实战
    • 五、一线大厂简历
    • 六、测试开发DevOps体系
    • 七、常用自动化测试工具
    • 八、JMeter性能测试
    • 九、总结(尾部小惊喜)


前言

1、关键字驱动框架简介

原理及特点:
①关键字驱动测试是数据驱动测试的一种改进类型,它也被称为表格驱动测试或者基于动作字的测试。
②主要关键字包括三类:被操作对象(Item)、操作行为(Operation)和操作值(Value),用面向对象形式可将其表现为 Item.Operation(Value)。

③将测试逻辑按照这些关键字进行分解,形成数据文件。

④用关键字的形式将测试逻辑封装在数据文件中,测试工具只要能够解释这些关键字即可对其应用自动化。

优势:
①执行人员可以不需要太多的技术:一旦框架建立,手工测试人员和非技术人员都可以很容易的编写自动化测试脚本。

②简单易懂:它存在 Excel 表格中,没有编码,测试脚本容易阅读和理解。关键字和操作行为这样的手工测试用例,使它变得更容易编写和维护。

③早期介入:可以在应用未提交测试之前,就可以建立关键字驱动测试用例对象库,从而减少后期工作。使用需求和其它相关文档进行收集信息,关键字数据表可以建立手工测试程序。

④代码的重用性:用关键字的形式将测试用例及数据进行组装并解释执行,提高代码的可重用性。

2、框架结构说明

框架结构:
整个测试框架分为四层,通过分层的方式,测试代码更容易理解,维护起来较为方便。

第一层是“测试工具层”:
util 包:用于实现测试过程中调用的工具类方法,例如读取配置文件、页面元素的操作方法、操作 Excel 文件、生成测试报告、发送邮件等。
conf 包:配置文件及全局变量。
log 目录:日志输出文件。
exception_pic 目录:失败用例的截图保存目录。

第二层是“服务层”:
相当于对测试对象的一个业务封装。对于接口测试,是对远程方法的一个实现;对于 UI 测试,是对页面元素或操作的一个封装。
action 包:封装具体的页面动作,如点击、输入文本等。

第三层是“测试用例逻辑层”:
该层主要是将服务层封装好的各个业务对象,组织成测试逻辑,进行校验。

bussiness_process 包:基于关键字的形式,实现单条、多条用例的测试脚本逻辑。
test_data 目录:Excel 数据文件,包含用例步骤、被操作对象、操作动作、操作值、测试结果等。

第四层是“测试场景层”:
将测试用例组织成测试场景,实现各种级别 cases 的管理,如冒烟,回归等测试场景。

main.py:本框架工程的运行主入口。

31

32

33

框架特点:
①基于关键字测试框架,即使不懂开发技术的测试人员也可以实施自动化测试,便于在整个测试团队中推广和使用自动化测试技术,降低自动化测试实施的技术门槛。

②使用外部测试数据文件,使用Excel管理测试用例的集合和每个测试用例的所有执行步骤,实现在一个文件中完成测试用例的维护工作。

③通过定义关键字、操作元素的定位方式和定位表达式和操作值,就可以实现每个测试步骤的执行,可以更加灵活地实现自动化测试的需求。
④基于关键字的方式,可以进行任意关键字的扩展,以满足更加复杂的自动化测试需求。

⑤实现定位表达式和测试代码的分离,实现定位表达式直接在数据文件中进行维护。
⑥框架提供日志功能,方便调试和监控自动化测试程序的执行。

3、框架代码实现

action 包

action 包为框架第二层“服务层”,相当于对测试对象的一个业务封装。对于接口测试,是对远程方法的一个实现;对于 UI 测试,是对页面元素或操作的一个封装。

page_action.py
本模块基于关键字格式,封装了页面操作的常用函数,如打开 APP、点击、输入文本等。

import traceback
import os
import time
from appium import webdriver
from util.get_desired_caps import get_desired_caps
from util.datetime_util import *
from util.find_element_util import *
from util.global_var import *
from util.log_util import *


DRIVER = ""


# 打开APP,获取webdriver对象
def open_app():
    global DRIVER
    desired_caps = get_desired_caps()
    DRIVER = webdriver.Remote(APPIUM_SERVER, desired_caps)


# 设定开始活动页
def open_start_activity(app_name, start_activity_name):
    global DRIVER
    DRIVER.start_activity(app_name, start_activity_name)


# 退出APP
def quit_app():
    global DRIVER
    DRIVER.quit()


# 在页面输入框中输入数据
def input_string(location_type, locator_expression, input_content):
    global DRIVER
    find_element(DRIVER, location_type, locator_expression).send_keys(input_content)


# 清除输入框默认内容
def clear(location_type, locator_expression):
    global DRIVER
    find_element(DRIVER, location_type, locator_expression).clear()


# 点击页面元素
def click(location_type, locator_expression):
    global DRIVER
    find_element(DRIVER, location_type, locator_expression).click()


# 断言界面源码是否存在某关键字或关键字符串
def assert_string_in_pagesource(assert_string):
    global DRIVER
    try:
        assert assert_string in DRIVER.page_source, "%s not found in page source!" % assert_string
        info("断言成功【关键字:{}】".format(assert_string))
    except:
        error("断言失败【关键字:{}】".format(assert_string))
        raise


# 强制等待
def sleep(sleep_seconds):
    time.sleep(int(sleep_seconds))


# 批量断言
def assert_app_list(location_type, locator_expression, assert_string):
    global DRIVER
    assert_string_list = assert_string.split(",")
    elements = find_element(DRIVER, location_type, locator_expression)
    for element in elements[:3]:
        assert element.text in assert_string_list


# 截图函数
def take_screenshot():
    global DRIVER
    # 创建当前日期目录
    dir = os.path.join(EXCEPION_PIC_PATH, get_chinese_date())
    if not os.path.exists(dir):
        os.makedirs(dir)
    # 以当前时间为文件名
    file_name = get_chinese_time()
    file_path = os.path.join(dir, file_name+".png")
    try:
        DRIVER.get_screenshot_as_file(file_path)
        # 返回截图文件的绝对路径
        return file_path
    except:
        print("截图发生异常【{}】".format(file_path))
        traceback.print_exc()
        return file_path

business_process 包

business_process 包是框架第三层“测试用例逻辑层”,该层主要是将服务层封装好的各个业务对象,组织成测试逻辑,进行校验。

case_process.py
测试用例文件的一行数据,拼接其中的操作动作、操作对象、操作值等关键字,形成与 page_action.py 中的函数相对应的字符串,并通过 eval() 转成表达式以执行用例。
记录该用例的测试结果,如测试执行结果、测试执行时间等。

如需数据驱动的用例集,则获取数据驱动的数据源集合,循环将每组数据传递给用例步骤。
如果遇到需要参数化的值 ${变量名},则根据数据驱动的数据源,根据变量名进行参数化。

import traceback
import re
from util.global_var import *
from util.log_util import *
from util.datetime_util import *
from util.excel_util import Excel
from action.page_action import *


# 执行单条测试用例(对应excel测试数据文件中的一行测试用例数据)
def execute_case(excel_file_path, case_data, test_data_source=None):
    # 用例数据格式校验
    if not isinstance(case_data, (list, tuple)):
        error("测试用例数据格式有误!测试数据应为列表或元组类型!【%s】" % case_data)
        case_data[CASESTEP_EXCEPTION_INFO_COL_NO] = "测试用例数据格式有误!应为列表或元组类型!【%s】" % case_data
        case_data[CASESTEP_TEST_RESULT_COL_NO] = "Fail"
    # 该用例无需执行
    if case_data[CASESTEP_IS_EXECUTE_COL_NO].lower() == "n":
        info("测试用例步骤【%s】无需执行" % case_data[CASESTEP_NAME_COL_NO])
        return
    # excel对象初始化
    if isinstance(excel_file_path, Excel):
        excel = excel_file_path
    else:
        excel = Excel(excel_file_path)
    # 获取各关键字
    operation_action = case_data[CASESTEP_ACTION_COL_NO]  # 操作动作(即函数名)
    locate_method = case_data[CASESTEP_LOCATE_METHOD_COL_NO]  # 定位方式
    locate_expression = case_data[CASESTEP_LOCATE_EXPRESSION_COL_NO]  # 定位表达式
    operation_value = case_data[CASESTEP_OPERATION_VALUE_COL_NO]  # 操作值
    # 由于数据驱动,需要进行参数化的值
    if test_data_source:
        if re.search(r"\$\{\w+\}", str(operation_value)):
            # 取出需要参数化的值
            key = re.search(r"\$\{(\w+)\}", str(operation_value)).group(1)
            operation_value = re.sub(r"\$\{\w+\}", test_data_source[key], str(operation_value))
            # 将参数化后的值回写excel测试结果中,便于回溯
            case_data[CASESTEP_OPERATION_VALUE_COL_NO] = operation_value
    # 拼接关键字函数
    if locate_method and locate_expression:
        if operation_value:
            func = "%s('%s', '%s', '%s')" % (operation_action, locate_method, locate_expression, operation_value)
        else:
            func = "%s('%s', '%s')" % (operation_action, locate_method, locate_expression)
    else:
        if operation_value:
            func = "%s('%s')" % (operation_action, operation_value)
        else:
            func = "%s()" % operation_action
    # 执行用例
    try:
        eval(func)
        info("测试用例步骤执行成功:【{}】 {}".format(case_data[CASESTEP_NAME_COL_NO], func))
        case_data[CASESTEP_TEST_RESULT_COL_NO] = "Pass"
    except:
        info("测试用例步骤执行失败:【{}】 {}".format(case_data[CASESTEP_NAME_COL_NO], func))
        case_data[CASESTEP_TEST_RESULT_COL_NO] = "Fail"
        error(traceback.format_exc())
        # 进行截图
        case_data[CASESTEP_EXCEPTION_PIC_DIR_COL_NO] = take_screenshot()
        # 异常信息记录
        case_data[CASESTEP_EXCEPTION_INFO_COL_NO] = traceback.format_exc()
    # 测试时间记录
    case_data[CASESTEP_TEST_TIME_COL_NO] = get_english_datetime()
    return case_data


if __name__ == "__main__":
    excel = Excel(TEST_DATA_FILE_PATH)
    excel.get_sheet("登录")
    all_data = excel.get_all_row_data()
    for data in all_data[1:]:
        execute_case(excel, data)

data_source_process.py:
本模块实现了获取数据驱动所需的数据源集合。

根据数据源 sheet 名,获取该 sheet 所有行数据,每行数据作为一组测试数据。
每行数据作为一个字典,存储在一个列表中。如 [{“登录用户名”: “xxx”, “登录密码”: “xxx”, …}, {…}, …]

from util.excel_util import Excel
from util.global_var import *
from util.log_util import *


# 数据驱动
# 每行数据作为一个字典,存储在一个列表中。如[{"登录用户名": "xxx", "登录密码": "xxx", ...}, {...}, ...]
def get_test_data(excel_file_path, sheet_name):
    # excel对象初始化
    if isinstance(excel_file_path, Excel):
        excel = excel_file_path
    else:
        excel = Excel(excel_file_path)
    # 校验sheet名
    if not excel.get_sheet(sheet_name):
        error("sheet【】不存在,停止执行!" % sheet_name)
        return
    result_list = []
    all_row_data = excel.get_all_row_data()
    if len(all_row_data) <= 1:
        error("sheet【】数据不大于1行,停止执行!" % sheet_name)
        return
    # 将参数化的测试数据存入全局字典
    head_line_data = all_row_data[0]
    for data in all_row_data[1:]:
        if data[-1].lower() == "n":
            continue
        row_dict = {}
        for i in range(len(data[:-1])):
            row_dict[head_line_data[i]] = data[i]
        result_list.append(row_dict)
    return result_list


if __name__ == "__main__":
    from util.global_var import *
    print(get_test_data(TEST_DATA_FILE_PATH, "搜索词"))
    # [{'搜索词': 'python', '断言词': 'python'}, {'搜索词': 'mysql', '断言词': 'mysql5.6'}]

main_process.py:
本模块基于 case_process.py 和 data_source_process.py,实现关键字驱动+数据驱动的测试用例集的执行。

suite_process():执行具体的测试用例步骤 sheet(如“登录” sheet、“搜索” sheet 等)
main_suite_process():执行“测试用例”主 sheet 的用例集。每行用例集对应一个用例步骤 sheet 和数据源 sheet。

from util.excel_util import *
from util.datetime_util import *
from util.log_util import *
from util.global_var import *
from bussiness_process.case_process import execute_case
from bussiness_process.data_source_process import get_test_data


# 执行具体的测试用例步骤sheet
def suite_process(excel_file_path, sheet_name, test_data_source=None):
    """
    :param excel_file_path: excel文件绝对路径或excel对象
    :param sheet_name: 测试步骤sheet名
    :param test_data_source: 数据驱动的数据源,默认没有
    :return:
    """
    # 记录测试结果统计
    global TOTAL_CASE
    global PASS_CASE
    global FAIL_CASE
    # 整个用例sheet的测试结果,默认为全部通过
    suite_test_result = True
    # excel对象初始化
    if isinstance(excel_file_path, Excel):
        excel = excel_file_path
    else:
        excel = Excel(excel_file_path)
    if not excel.get_sheet(sheet_name):
        error("sheet【】不存在,停止执行!" % sheet_name)
        return
    # 获取测试用例sheet的全部行数据
    all_row_data = excel.get_all_row_data()
    if len(all_row_data) <= 1:
        error("sheet【】数据不大于1行,停止执行!" % sheet_name)
        return
    # 标题行数据
    head_line_data = all_row_data[0]
    # 切换到测试结果明细sheet,准备写入测试结果
    if not excel.get_sheet("测试结果明细"):
        error("【测试结果明细】sheet不存在,停止执行!")
        return
    excel.write_row_data(head_line_data, None, True, "green")
    # 执行每行的测试用例
    for row_data in all_row_data[1:]:
        result_data = execute_case(excel, row_data, test_data_source)
        # 无需执行的测试步骤,跳过
        if result_data is None:
            continue
        TOTAL_CASE += 1
        if result_data[CASESTEP_TEST_RESULT_COL_NO].lower() == "fail":
            suite_test_result = False
            FAIL_CASE += 1
        else:
            PASS_CASE += 1
        excel.write_row_data(result_data)
    # 切换到测试结果统计sheet,写入统计数据
    if not excel.get_sheet("测试结果统计"):
        error("【测试结果统计】sheet不存在,停止执行!")
        return
    excel.insert_row_data(1, [TOTAL_CASE, PASS_CASE, FAIL_CASE])
    return excel, suite_test_result


# 执行【测试用例】主sheet的用例集
def main_suite_process(excel_file_path, sheet_name):
    # 初始化excel对象
    excel = Excel(excel_file_path)
    if not excel:
        error("excel数据文件【%s】不存在!" % excel_file_path)
        return
    if not excel.get_sheet(sheet_name):
        error("sheet名称【%s】不存在!" % sheet_name)
        return
    # 获取所有行数据
    all_row_datas = excel.get_all_row_data()
    if len(all_row_datas) <= 1:
        error("sheet【%s】数据不大于1行,停止执行!" % sheet_name)
        return
    # 标题行数据
    head_line_data = all_row_datas[0]
    for row_data in all_row_datas[1:]:
        # 跳过不需要执行的测试用例集
        if row_data[TESTCASE_IS_EXECUTE_COL_NO].lower() == "n":
            info("#" * 50 + " 测试用例集【%s】无需执行!" % row_data[TESTCASE_CASE_NAME_COL_NO] + "#" * 50 + "\n")
            continue
        # 记录本用例集的测试时间
        row_data[TESTCASE_TEST_TIME_COL_NO] = get_english_datetime()
        # 校验用例步骤sheet名是否存在
        if row_data[TESTCASE_CASE_STEP_SHEET_NAME_COL_NO] not in excel.get_all_sheet():
            error("#" * 50 + " 用例步骤集【%s】不存在! " % row_data[TESTCASE_CASE_STEP_SHEET_NAME_COL_NO] + "#" * 50 + "\n")
            row_data[TESTCASE_TEST_RESULT_COL_NO] = "Fail"
            excel.write_row_data(head_line_data, None, True, "red")
            excel.write_row_data(row_data)
            continue
        # 判断本测试用例集是否进行数据驱动
        if row_data[TESTCASE_DATA_SOURCE_SHEET_NAME_COL_NO]:
            # 校验测试数据集sheet名是否存在
            if row_data[TESTCASE_DATA_SOURCE_SHEET_NAME_COL_NO] not in excel.get_all_sheet():
                error("#" * 50 + " 测试数据集【%s】不存在! " % row_data[TESTCASE_DATA_SOURCE_SHEET_NAME_COL_NO] + "#" * 50 + "\n")
                row_data[TESTCASE_TEST_RESULT_COL_NO] = "Fail"
                excel.write_row_data(head_line_data, None, True, "red")
                excel.write_row_data(row_data)
                continue
            # 获取测试数据集
            test_data_source = get_test_data(excel, row_data[TESTCASE_DATA_SOURCE_SHEET_NAME_COL_NO])
            # 每条数据进行一次本用例集的测试
            for data_source in test_data_source:
                info("-" * 50 + " 测试用例集【%s】开始执行!" % row_data[TESTCASE_CASE_NAME_COL_NO] + "-" * 50)
                excel, test_result_flag = suite_process(excel, row_data[TESTCASE_CASE_STEP_SHEET_NAME_COL_NO], data_source)
                # 记录本用例集的测试结果
                if test_result_flag:
                    info("#" * 50 + " 测试用例集【%s】执行成功! " % row_data[TESTCASE_CASE_NAME_COL_NO] + "#" * 50 + "\n")
                    row_data[TESTCASE_TEST_RESULT_COL_NO] = "Pass"
                else:
                    error("#" * 50 + " 测试用例集【%s】执行失败! " % row_data[TESTCASE_CASE_NAME_COL_NO] + "#" * 50 + "\n")
                    row_data[TESTCASE_TEST_RESULT_COL_NO] = "Fail"
                # 全部测试步骤结果写入后,最后写入本用例集的标题行和测试结果行数据
                # 切换到“测试结果明细”sheet,以写入测试执行结果
                excel.get_sheet("测试结果明细")
                excel.write_row_data(head_line_data, None, True, "red")
                excel.write_row_data(row_data)
        # 本用例集无需数据驱动
        else:
            info("-" * 50 + " 测试用例集【%s】开始执行!" % row_data[TESTCASE_CASE_NAME_COL_NO] + "-" * 50)
            excel, test_result_flag = suite_process(excel, row_data[TESTCASE_CASE_STEP_SHEET_NAME_COL_NO])
            # 记录本用例集的测试结果
            if test_result_flag:
                info("#" * 50 + " 测试用例集【%s】执行成功! " % row_data[TESTCASE_CASE_NAME_COL_NO] + "#" * 50 + "\n")
                row_data[TESTCASE_TEST_RESULT_COL_NO] = "Pass"
            else:
                error("#" * 50 + " 测试用例集【%s】执行失败! " % row_data[TESTCASE_CASE_NAME_COL_NO] + "#" * 50 + "\n")
                row_data[TESTCASE_TEST_RESULT_COL_NO] = "Fail"
            # 全部测试步骤结果写入后,最后写入本用例集的标题行和测试结果行数据
            # 切换到“测试结果明细”sheet,以写入测试执行结果
            excel.get_sheet("测试结果明细")
            excel.write_row_data(head_line_data, None, True, "red")
            excel.write_row_data(row_data)
    return excel


if __name__ == "__main__":
    from util.report_util import create_excel_report_and_send_email
    # excel, _ = suite_process(TEST_DATA_FILE_PATH, "进入主页")
    # excel, _ = suite_process(excel, "登录")
    excel = main_suite_process(TEST_DATA_FILE_PATH, "测试用例")
    create_excel_report_and_send_email(excel, "xxxxxxx@qq.com", "app自动化测试", "请查收附件:app自动化测试报告")
下面是我整理的2023年最全的软件测试工程师学习知识架构体系图

一、Python编程入门到精通

请添加图片描述

二、接口自动化项目实战

请添加图片描述

三、Web自动化项目实战

请添加图片描述

四、App自动化项目实战

请添加图片描述

五、一线大厂简历

请添加图片描述

六、测试开发DevOps体系

请添加图片描述

七、常用自动化测试工具

请添加图片描述

八、JMeter性能测试

请添加图片描述

九、总结(尾部小惊喜)

奋斗是燃烧心灵的力量,是追寻梦想的征程。即使困顿,也要坚守初心,勇往直前。每一次努力都是成长的催化剂,每一次奋斗都将绽放出灿烂的人生之花。

站在人生的起点,勇敢追逐梦想。不畏困难,不惧失败,执着奋斗的脚步踏遍千山万水。坚持信念,拼尽全力,终将在辉煌与成功的殿堂上书写属于自己的传世之作!

不忘初心,坚守梦想之航。即使身陷逆境,也要勇往直前,努力奋斗。相信自己的能力,拥抱挑战的机会,用汗水浇灌成就。奋斗不止于一时,而是人生的永恒追求!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/872630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Stm32-使用TB6612驱动电机及编码器测速

这里写目录标题 起因一、电机及编码器的参数二、硬件三、接线四、驱动电机1、TB6612电机驱动2、定时器的PWM模式驱动电机 五、编码器测速1、定时器的编码器接口模式2、定时器编码器模式测速的原理3、编码器模式的配置4、编码器模式相关代码5、测速方法 六、相关问题以及解答1、…

关于Cesium的常见需求整理之点位和弹窗(点位弹窗)

一、点位上图 ①在Cesium中&#xff0c;每个自定义的地图元素被视为一个entity对象&#xff0c;如果我们要添加点位到地图上&#xff0c;那就必须先创建一个entity对象。 var entity new Cesium.Entity({position: position, });以上代码我们创建了一个entity对象&#xff0…

Autosar通信入门系列06-聊聊CAN通信的线与机制与ACK应答

本文框架 1. 概述2. CAN通信的线与机制3. ACK应答机制理解 1. 概述 本文为Autosar通信入门系列介绍&#xff0c;如您对AutosarMCAL配置&#xff0c;通信&#xff0c;诊断等实战有更高需求&#xff0c;可以参见AutoSar 实战进阶系列专栏&#xff0c;快速链接&#xff1a;AutoSa…

数据库基础(增删改查)

目录 MySQL 背景知识 数据库基础操作 1.创建数据库 2.查看所有数据库 3.选中指定的数据库 4.删除数据库 数据库表操作 MySQL的数据类型 1.创建表 3.查看指定表的结构 4.删除表 增删改 新增操作 修改(Updata) 删除语句 面试题 查询操作 指定列查询 查询的列为表达式…

系统设计:通用思路之4S分析法

1.系统设计 系统设计是一个定义系统架构、功能模块、服务及接口和数据存储等满足特定需求的过程。 与面向对象设计不同的是&#xff0c;面向对象设计通常是对于某个特定功能模块的设计&#xff0c;通常要求设计类图关系、接口关系、实现关系等涉及具体代码层面的设计&#xff…

C语言库函数之 qsort 讲解、使用及模拟实现

引入 我们在学习排序的时候&#xff0c;第一个接触到的应该都是冒泡排序&#xff0c;我们先来复习一下冒泡排序的代码&#xff0c;来作为一个铺垫和引入。 代码如下&#xff1a; #include<stdio.h>void bubble_sort(int *arr, int sz) {int i 0;for (i 0; i < sz…

基于chatgpt动手实现一个ai_translator

动手实现一个ai翻译 前言 最近在极客时间学习《AI 大模型应用开发实战营》&#xff0c;自己一边跟着学一边开发了一个进阶版本的 OpenAI-Translator&#xff0c;在这里简单记录下开发过程和心得体会&#xff0c;供有兴趣的同学参考&#xff1b; ai翻译程序 版本迭代 在学习…

C语言必会题目(2)

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 今天继续分享C语言必会的题目&#xff0c;上一篇文章主要是一些选择题&#xff0c;而今天我们主要内容为编程题的推荐与讲解 准备好迎接下面的题了吗&#xff1f;开始发车了&#xff01;&#xff01;&#xff01; 输入…

pytest运行时参数说明,pytest详解,pytest.ini详解

一、Pytest简介 1.pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要有一下几个特点&#xff1a; 简单灵活&#xff0c;容易上手&#xff0c;支持参数化 2.能够支持简单的单元测试和复杂的功能测试&#xff0c;还可以用来做selenium、appium等自动化测试&#xf…

zookeeper案例

目录 案例一&#xff1a;服务器动态上下线 服务端&#xff1a; &#xff08;1&#xff09;先获取zookeeper连接 &#xff08;2&#xff09;注册服务器到zookeeper集群&#xff1a; &#xff08;3&#xff09;业务逻辑&#xff08;睡眠&#xff09;&#xff1a; 服务端代码…

提高生产力 | Apifox 数据结构验证最佳实践

目录 实践场景 定义返回响应 场景数据准备 校验响应数据 总结 在设计接口的过程中&#xff0c;响应数据需要和返回响应规范一一对应。这样能够确保接口的一致性和可靠性&#xff0c;并且方便接口的使用和维护&#xff0c;即使在后续迭代过程中出现问题&#xff0c;开发人员…

zabbix监控安装部署

目录 一、环境 二、配置 1.配置yum源&#xff0c;这里用的清华的 2.过滤一下安装包&#xff0c;查看依赖包 安装依赖包 3.配置数据库 开机自启 创建数据库 创建用户 授权 导入数据到数据库 查看zabbix数据库有没有表和数据 4.修改zabbix配置文件 1.修改zabbix配置…

【Java】常见面试题:多线程

文章目录 1. 谈谈进程和线程之间的区别【高频】2. java中有哪些方式来创建线程&#xff1f;3. run和start的区别【经典面试题】4. Java线程的状态5. 【线程不安全的原因】6. 就以count为例&#xff1a;一个线程加锁、一个线程不加锁&#xff0c;此时能否保证线程的安全呢&#…

client-go实战之十二:选主(leader-election)

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《client-go实战》系列的第十二篇&#xff0c;又有一个精彩的知识点在本章呈现&#xff1a;选主(leader-election)在解释什么是选主之前&…

Keepalived源码安装

文章目录 Keepalived源码安装安装准备缺少OpenSSL解决方法 Keepalived 源码安装 安装准备 tar zxf keepalived-2.2.8.tar.gz /root/ ll drwxrwxr-x. 10 1000 1000 4096 Aug 9 18:29 keepalived-2.2.8 #进入目录执行以下命令查看帮助 ./configure --help #重要编译参数 -…

QT学习笔记-oracle oci数据库驱动交叉编译并移植到ARM开发板

QT学习笔记-oracle oci数据库驱动交叉编译并移植到RK3568ARM开发板 0、背景1、搭建交叉编译环境2、交叉编译过程3、把数据库驱动部署到目标系统中 0、背景 在上一文《QT学习笔记-QT安装oracle oci驱动》中介绍了在Windows环境下使用QT访问oracle数据库时遇到驱动无法加载问题的…

kingbase:数据库启动状态

1 启停KingbaseES数据库 Linux下通过系统服务&#xff1a; root用户执行&#xff1a; service kingbase8d stop/start/restart ——注册服务的情况下 Linux下通过安装用户&#xff1a; 安装用户执行&#xff1a; sys_ctl stop/start/restart -D data路径 2 查看数据库当…

UI自动化环境的搭建(python+pycharm+selenium+chrome)

最近在做一些UI自动化的项目&#xff0c;为此从环境搭建来从0到1&#xff0c;希望能够帮助到你&#xff0c;同时也是自我的梳理。将按照如下进行开展&#xff1a; 1、python的下载、安装&#xff0c;python环境变量的配置。 2、pycharm开发工具的下载安装。 3、selenium的安装。…

【Java】一只小菜坤的编程题之旅【3】

文章目录 1丶判定是否互为字符重排2、杨辉三角3丶某公司的1个面试题&#xff08;字符串包含问题&#xff09; 1丶判定是否互为字符重排 这个题我们用一个非常简单的思想就能实现&#xff0c;我们先将字符串转换为字符数组&#xff0c;然后对字符数组进行排序&#xff0c;然后再…

Codeforces Round 893 (Div. 2)ABC

Codeforces Round 892 (Div. 2) 目录 A. United We Stand题目大意思路代码 B. Olya and Game with Arrays题目大意思路代码 C. Another Permutation Problem题目大意思路代码 A. United We Stand 题目大意 给你一个数组&#xff0c;把这个数组分成两个数组a和b&#xff0c;使…