测试开发 ======== kunlun-data文件夹 ------------------- 首次安装Kunlun平台后, 执行 ``kunlun start`` , 平台将自动创建 ``C:\kunlun-data`` 文件夹, 用户也可以自行创建此文件夹。 ``C:\kunlun-data`` 包含以下文件或文件夹. 1. ``db.sqlite3`` :数据库文件, 保存测试记录. 2. ``logs`` :测试日志文件夹, 保存测试过程中产生的测试日志, 以及保存一些临时文件. 3. ``tftpboot`` : ``tftp`` 服务与 ``ftp`` 服务的根文件目录. 定制用户界面 ------------- Win10用户可以通过以下方式将 ``测试程序示例`` 下载到 ``C:\kunlun-data`` 文件夹 :: cd C:\kunlun-data git clone https://gitee.com/robinwu0607/kunlun_scripts * ``configs`` 中包含界面定制代码. * ``demo`` 中包含演示测试代码. .. image:: ../_static/用户界面/hostname.png 用于演示的 ``autotest.py`` 文件的内容示例如下, 用户可以根据业务需要进行增加、修改或是拷贝:: # 导入接口函数库 from kunlun import lib # 函数名必须是 main() def main(): # 从lib.get_configuration()获取根实例kun # tftp: 为True时将启动tftp服务, 默认为False # ftp: 为True时将启动ftp服务, 默认为False kun = lib.get_configuration(tftp=False, ftp=False) # add_station: 在根实例Kl下增加一个Station工站 # name: 工站的名称 # desc: 工站的描述说明 # recycle: 为True时, Container测试PASS后, 将会自动重新开始测试, 免人工反复点击开始按钮.默认值为False # image: 工站的封面图片.demo是项目名称, 建议图片的格式为.jpg或是.png station = kun.add_station(name="PCBA", desc="PCBA功能测试", recycle=False, image=r"demo\bee.jpg", dense=True) # 设置工站的测试任务所关联的用户代码路径. # demo是项目名称, sequence是文件, 平台将调用sequence.py下的函数main_sequence()作为入口函数 station.add_sequence("demo.pcba") station.add_connection(name="UDS", protocol="DUMMY") # 设置工站的硬件参数, 用户在代码中可以使用lib.get_params("host")获取到参数的值 station.add_params_data(host="192.168.0.1", password="root") # 用循环的方式连续添加Container工位 for i in range(4): # add_container: 在工站实例station下增加一个Container工位. # name: 工位的名称, 工位的名称动态累加 container = station.add_container(name="UUT{:02d}".format(i)) # 设置工位的硬件参数.工位会继承工站的硬件参数, 同时可以覆盖工站的参数, 或是新增专用的参数. container.add_params_data(ip="192.168.1.{}".format(i), test="hello world") # 增加一个Connection连接, 连接的协议为DUMMY, 将调用windows的cmd.exe窗口. container.add_connection(name="UUT", protocol="DUMMY") # 增加一个Connection连接, 连接的协议为SSH, 目标主机ip为192.168.0.2, 登入用户名为root, 密码为root. container.add_connection(name="SSH", protocol="SSH", host="192.168.0.2", username="root", password="root", prompt="$") # 增加一个Connection连接, 连接的协议为TELNET, 目标主机ip为192.168.0.3, 端口为2009. container.add_connection(name="TNT", protocol="TELNET", host="192.168.0.3", port=2009, username="root", password="root", prompt="$") # 增加一个Connection连接, 连接的协议为SERIAL, 目标端口为COM1, 波特率为115200. container.add_connection(name="SER", protocol="SERIAL", serial="COM1", baudrate=115200) # 增加MEASURE窗口 container.show_measure_panel() # 在根实例Kl下增加第二个Station工站 station = kun.add_station(name="FCT", desc="FCT测试", recycle=False) station.add_sequence("demo.fct") for i in range(4): container = station.add_container(name="UUT{:02d}".format(i)) container.add_connection(name="UUT", protocol="DUMMY") # 增加MEASURE窗口 container.show_measure_panel() # 增加STEP窗口 container.show_step_panel() # 增加INFO窗口 container.show_info_panel() 需要注意的是:每次对 ``autotest.py`` 进行修改, 必须使用 ``kunlun start`` 重启服务, 修改后的内容才会生效. 需要再次强调的是, 平台会根据 ``add_sequence()`` 中的入参调用对应项目下的 ``.py`` 文件的 ``main_sequence()`` 函数作为入口函数. 开发者模式与生产模式 -------------------- 在测试主界面, 用户可以自由切换 ``生产模式`` 与 ``开发模式`` (默认为 ``生产模式`` ), 平台后台将根据选择的模式, 自动处理调用 ``kunlun_scripts`` 或是 ``develop`` 文件夹下测试代码. .. image:: ../_static/用户界面/product-mode.png .. image:: ../_static/用户界面/develop-mode.png 需要强调的是:每次页面刷新后, 测试模式将会默认切换至 ``生产模式`` . 测试服务 -------- 平台提供 ``FTP`` 与 ``TFTP`` 服务. FTP服务 ^^^^^^^ 用户在定制界面时, 若设置 ``lib.get_configuration(ftp=True)`` , 启动平台时, FTP服务也将启动. FTP的默认文件夹是 ``C:\kunlun-data\tftpboot`` , 用户名密码为: ``autotest/autotest`` . TFTP服务 ^^^^^^^^ 用户在定制界面时, 若设置 ``lib.get_configuration(tftp=True)`` , 启动平台时, TFTP服务也将启动. FTP的默认文件夹是 ``C:\kunlun-data\tftpboot`` . 需要注意的是: 1. 当 ``lib.get_configuration(ftp=True, tftp=True)`` 时, FTP服务与TFTP服务将同时启动, 不冲突. 2. ``FTP服务`` 使用端口 ``21``, ``TFTP服务`` 使用端口 ``69``. 测试代码开发方案 ----------------- 用户的代码存放于 ``C:\kunlun-data\kunlun_scripts`` 或是 ``C:\kunlun-data\develop`` 下. 给开发者建议: 1. 用户项目下的文件夹与文件, Python代码开发规范参考PEP8规范, PEP8链接为: https://www.python.org/dev/peps/pep-0008/ 2. 用户项目下的每一个文件夹, 都包含文件 ``__init__.py`` . 3. 用户项目文件夹的名称与实际项目名称保持一致. 4. 使用 ``git`` 等版本工具管理测试代码. 基于不同的测试需求与目标, 用户可以采用快速开发方案或是测试序列编排方案. 小型项目快速开发 ^^^^^^^^^^^^^^^^^ 建议采用快速开发方案的是: 1. 相对独立的项目(较少与其他项目复用代码). 2. 测试命令行小于或等于20条的项目. 快速开发方案的演示代码可以参考 ``C:\kunlun-data\kunlun_scripts\demo\fct.py`` . 以下截取部分代码片段进行说明:: from kunlun import lib import time # 获取事件日志接口 log = lib.get_event_logger() # 定义入口函数, 每个文件只有一个入口函数. def main_sequence(): log.debug("welcome to main sequence") container_name = lib.get_container_name() log.debug(container_name) ans = lib.ask_question("输入序列号:") log.debug("ask_question: [%s]", ans) ans = lib.ask_question("选择产品类型:", options=["12-3456-78", "98-7654-32"]) log.debug("ask_question choose: (%s)", ans) ans = lib.ask_question("选择产品类型:", options=["12-3456-78", "98-7654-32"], multiple=True) log.debug("ask_question multiple choose: (%s)", ans) ans = lib.ask_questions(["输入序列号:", "输入MAC:", "输入编码:"]) log.debug("ask_questions: (%s)", ans) lib.ud.hello = "good" uut = lib.conn.UUT uut.open() log.debug("run test1: dir") uut.send("dir\r", expect=">", timeout=10) time.sleep(1) log.debug(lib.get_params()) lib.add_test_data(sernum="1234567890", uuttype="DEMO", area="DEMO") run_test2() run_test4() return def run_test2(): uut = lib.conn.UUT uut.open() log.debug("run test2") uut.send("dir\r", expect=">", timeout=10) if "UUT01" in lib.get_container_name(): lib.set_step_name("Test Step2") raise Exception("run test failed") time.sleep(2) return def run_test4(): lib.set_display1("SERNUM: 1234567890") lib.set_display2("UUTTYPE: 12-3456-78") log.debug("userdict1: {}".format(lib.ud.hello)) log.debug("userdict2: {}".format(lib.ud)) return 大型项目测试编排 ^^^^^^^^^^^^^^^^ 建议采用测试序列编排方案的是: 1. 大型项目的子项目(较多与其他项目复用代码). 2. 持续演进的项目. 3. 需要实施较多测试策略的项目. 4. 测试命令行大于20条的项目. 测试序列编排方案的演示代码可以参考 ``C:\kunlun-data\kunlun_scripts\demo\pcba.py`` . 以下截取部分代码片段供参考:: from kunlun import lib import time # 获取事件日志接口 log = lib.get_event_logger() # 定义入口函数, 每个文件只有一个入口函数. def main_sequence(): # 增加一个根测试序列sequence, 并设置名称为MAIN SEQ seq = lib.get_sequence_definition("MAIN SEQ") # 根序列增加一个step, 并设置此step名称为RUN TEST, 如果测试失败, 则失败项为RUN TEST seq.add_step(run_test, name="RUN TEST") # 根序列增加一个step, 并传参数kws给step seq.add_step(run_test1, name="run test1", kws={"name": "gps test", "value": "cpu test"}) # 根序列增加一个子测试序列, 并设置名称为SUB MAIN SEQ # in_parallel: 并行测试标识, 为True时, 将与 下一个step/测试序列 并行执行 # 测试循环次数设置为3次 sub_seq = seq.add_sequence("SUB MAIN SEQ", in_parallel=True, cycle_count=1) # 子序列增加一个step sub_seq.add_step(run_test2, name="run test2-1") # 子序列增加一个step sub_seq.add_step(run_test2, name="run test2-2") # 根序列增加一个step # 测试循环时间为30秒 seq.add_step(run_test3, name="RUN TEST3", cycle_time=1) # 根序列增加一个step. seq.add_step(run_test4, name="run TEST4") # 返回根序列 return seq def run_test(): log.debug("welcome to main sequence") container_name = lib.get_container_name() log.debug(container_name) ans = lib.ask_question("输入序列号:") log.debug("ask_question: [%s]", ans) ans = lib.ask_question("选择产品类型:", options=["12-3456-78", "98-7654-32"]) log.debug("ask_question choose: (%s)", ans) ans = lib.ask_question("选择产品类型:", options=["12-3456-78", "98-7654-32"], multiple=True) log.debug("ask_question multiple choose: (%s)", ans) ans = lib.ask_questions(["输入序列号:", "输入MAC:", "输入编码:"]) log.debug("ask_questions: (%s)", ans) lib.ud.hello = "good" return def run_test1(name="name", value="value"): log.debug("name: {}".format(name)) log.debug("value: {}".format(value)) uut = lib.conn.UUT uut.open() log.debug("run test1: dir") uut.send("dir\r", expect=">", timeout=10) time.sleep(1) # log.debug(lib.get_json_params("Sheet1", "param1")) # log.debug(lib.get_json_params("Sheet1", "param*")) # log.debug(lib.get_json_params("Sheet1", "*_test")) # log.debug(lib.get_json_params("Sheet1", "*")) log.debug(lib.get_params()) return def run_test2(): uut = lib.conn.UUT log.debug("run test2") uut.send("dir\r", expect=">", timeout=10) if "fail" in uut.buf: raise Exception("run test failed") time.sleep(2) return def run_test3(): log.debug("run test3") time.sleep(2) return def run_test4(): lib.set_display1("SERNUM: 1234567890") lib.set_display2("UUTTYPE: 12-3456-78") lib.add_test_data(sernum="1234567890", uuttype="DEMO", area="DEMO") log.debug("userdict1: {}".format(lib.ud.hello)) log.debug("userdict2: {}".format(lib.ud)) return 需要说明的是: ``lib.get_sequence_definition()`` 中可以承载较多的测试策略, 用户可以将精力投入到测试业务代码本身, 聚焦更有价值的部分, 测试策略交给平台处理. 需要注意的是: 入口函数 ``main_sequence()`` 必须 ``return`` 根测试序列 ``seq`` 给到平台, 否则平台将无法执行测试序列. 导入其他pip依赖包 ^^^^^^^^^^^^^^^^^^^^^ 直接使用 ``pip install`` 安装对应依赖包即可. 命令行kunlun run ------------------- 使用命令行执行测试用例, 方便在测试程序发布前, 快速单独验证测试代码, 及时发现代码问题:: Usage: kunlun run [prodcut] [case] [--param] [--key value] [--develop] [--help] ``kunlun run --help`` 可以查看帮助信息. ``kunlun run [prodcut] [case] --param --key value`` 可以注入参数到测试用例。 ``kunlun run [prodcut] [case] --develop`` 可以调用开发模式下的测试用例。 以项目 ``demo`` 为例, 首先需要在项目下创建文件夹 ``testcase``, 得到 ``demo/testcase/``. ``demo`` 代码中可用的示例:: kunlun run demo test_demo TestCase的写法: 1. class类结构. class类结构式测试用例 ^^^^^^^^^^^^^^^^^^^^^^^ 在 ``demo/testcase/`` 文件夹下创建 ``.py`` 文件, 文件中创建 ``class TestCase(lib.TestCase)`` 类, 需要继承 ``lib.TestCase`` . 运行中, 平台会调用 ``setup()``, 再调用 ``run()``, 无论结果是PASS还是FAIL, 最后调用 ``teardown()``, 测试用例如下:: from kunlun import lib import time # 获取事件日志接口 log = lib.get_event_logger() class TestCase(lib.TestCase): """This is the Test Case document.""" uut = None def __init__(self) -> None: super().__init__() def setup(self): log.info("it is setup") # add temp connection for use. lib.add_connection(name="SSH", protocol="SSH", host="172.28.247.192", username="lenovo", password="lenovo", prompt="$") self.uut = lib.conn.SSH self.uut.open() def teardown(self): log.info("it is teardown") self.uut.close() def run(self): log.info("run demo cli") for i in range(3): self.uut.send("pwd\r", expect=[">", "$"], timeout=30) time.sleep(2) 需要说明的是, 方法 ``setup()`` , ``run()`` 与 ``teardown()`` 都不能定义入参. 菜单栏kunlun menu ------------------- 使用指令 ``kunlun menu`` 可以进入菜单栏模式。 菜单栏模式是 ``kunlun run`` 的另外一种表现形式, 方便用户使用, 避免记忆复杂的指令集. ``kunlun run`` 中的 ``class类结构式测试用例`` 中,如果定义了方法 ``menu_list()``, 即可以在 ``kunlun menu`` 中体现. 具体用法参考: ``demo\testcase\test_demo.py`` . 以下是 ``demo`` 代码中的示例:: def menu_list(self): return [ ("kunlun run demo test_demo", "执行DEMO程序1"), ("kunlun run demo test_demo", "执行DEMO程序2"), ] kunlun-autotest> kunlun menu |--------------------------------------------------------| |---------------- KunLun AutoTest MENU ------------------| |--------------------------------------------------------| current avaiable project: 0 -- go to upper menu 1 -- demo ctrl_c -- exit Input your choice: 1 |--------------------------------------------------------| |---------------- KunLun AutoTest MENU ------------------| |--------------------------------------------------------| demo avaiable case: 0 -- go to upper menu 1 -- test_demo 2 -- test_demo2 ctrl_c -- exit Input your choice: 1 |--------------------------------------------------------| |---------------- KunLun AutoTest MENU ------------------| |--------------------------------------------------------| demo test_demo avaiable item: 0 -- go to upper menu 1 -- 执行DEMO程序1 2 -- 执行DEMO程序2 3 -- 执行DEMO程序3 4 -- 执行DEMO程序4 5 -- 执行DEMO程序5 6 -- 执行DEMO程序6 7 -- 执行DEMO程序7 8 -- 执行DEMO程序8 9 -- 执行DEMO程序9 10 -- 执行DEMO程序10 11 -- 执行DEMO程序11 ctrl_c -- exit Input your choice: 图形化编程 Graphical Programming ---------------------------------- 尝试引入图形化编程来简化测试开发, 当前图形化编程只能完成简易的测试开发, 后续再慢慢完善. .. image:: ../_static/测试开发/gp-menu.png 通过点击菜单进入对应图形化编程界面. 用户可以在以下地址下载测试程序示例. ``https://gitee.com/robinwu0607/kunlun_scripts`` Configs Editor ^^^^^^^^^^^^^^^^^^ Configs Editor用来定制测试界面, 文件保存在 ``configs`` 中. .. image:: ../_static/测试开发/gp-configs.png TestCase Editor ^^^^^^^^^^^^^^^^^^ TestCase Editor用来开发测试用例, 文件保存在 ``demo/testcase`` 中。 .. image:: ../_static/测试开发/gp-testcase.png Sequence Editor ^^^^^^^^^^^^^^^^^^ Sequence Editor用来开发测试序列, 文件保存在 ``demo/sequence`` 中。 .. image:: ../_static/测试开发/gp-sequence.png