接口函数
模拟键盘操作
可以发送ASCII码模拟键盘操作, 示例代码如下:
uut.send(f"{lib.CTRL_C}", expect=">", timeout=10)
uut.send(f"{lib.ESC}\r", expect=">", timeout=10)
可用的清单如下:
lib.CTRL_A # 键盘ctrl + 字母A键, 以下组合键意义相同.
lib.CTRL_B
lib.CTRL_C
lib.CTRL_D
lib.CTRL_E
lib.CTRL_F
lib.CTRL_G
lib.CTRL_H
lib.CTRL_I
lib.CTRL_J
lib.CTRL_K
lib.CTRL_L
lib.CTRL_M
lib.CTRL_N
lib.CTRL_O
lib.CTRL_P
lib.CTRL_Q
lib.CTRL_R
lib.CTRL_S
lib.CTRL_T
lib.CTRL_U
lib.CTRL_V
lib.CTRL_W
lib.CTRL_X
lib.CTRL_Y
lib.CTRL_Z
lib.ESC # 键盘Escape按键, 即ESC键
lib.UP # 方向键, 向上
lib.DOWN # 方向键, 向下
lib.RIGHT # 方向键, 向右
lib.LEFT # 方向键, 向左
lib.VERSION
获取当前KunLun AutoTest的版本信息, 例如: v23.10.4 .
lib.USERNAME
获取当前测试电脑的登入用户名信息, 例如: lenovo .
lib.HOSTNAME
获取当前测试电脑的名称信息, 例如: desktop1tp185d , 需要说明的是: 这个名称是”修正”后的名称.
lib.PLATFORM
获取当前测试电脑的操作系统类型信息, 它是 WIN 或者是 LINUX 。
lib.DATA_PATH
获取当前kunlun-data的绝对路径, 即 ~/kunlun-data 。
lib.SCRIPT_PATH
获取当前开发模式的测试程序所在的绝对路径。
即: ~/kunlun-data/kunlun_scripts .
lib.LOG_PATH
获取当前测试的日志所在的绝对路径+当前测试时间戳, 它并不是一个路径, 它的作用是: 用户可以拷贝自定义的文件到日志的路径下, 方便在Test Data页面下载。
例如: ~/kunlun-data/logs/hostname/FT-UUT00/2020/10/01/20201001-120100-FT-UUT00- .
lib.ud
lib.ud 是一个全局字典userdict, 可以在测试代码的任意位置使用。
典型应用场景: 用户定义多个函数, 函数间的变量传递就会变得复杂, 使用 lib.ud 可以轻松解决这个问题。
lib.ud 使用起来也很方便, 如下所示:
lib.ud.test_spec = 123: 设置test_spec值为123。spec = lib.ud.test_spec获取test_spec的值, 并保存在变量spec。
需要说明的是:lib.ud 支持任意级层的赋值, 如 lib.ud.test.ft.result.name = "PASS" 。
lib.pa
返回当前项目下的JSON文件中的值, json的命名必须是 params.json , 如当前项目为 demo , 则JSON文件的路径为 demo/params.json 。
lib.pa 与接口函数 lib.get_json_params() 的相同点都是获取 params.json 文件中的值, 不同的在于:
lib.pa使用字典的形式获取, 当JSON定义的参数包含空格时, 会自动使用下划线_代替空格.lib.get_json_params()通过函数调用的形式获取, 当入参的值包含空格或是特殊字符时, 推荐用此法.
JSON内容示例如下:
{
"lab": [
{
"description": "it is description2",
"name": "hello",
"value": "world"
}
]
}
如果需要获取到 lab 下的 name 为 hello 的值, 可以用以下两种方式:
value = lib.get_json_params("lab", "hello")value = lib.pa.lab.hello
lib.xlsx
返回当前项目下的XLSX文件中的值, XLSX的命名必须是 measure.xlsx , 如当前项目为 demo ,
则XLSX文件的路径为 demo/measure.xlsx .
lib.conn
lib.conn 是一个连接池, 保存着用户在 hostname.py 中为当前 container工位 定义的所有连接。
例如:
用户定义了
add_connection(name="UUT"), 则使用uut = lib.conn.UUT可以获取此连接实例。用户定义了
add_connection(name="REF"), 则使用uut = lib.conn.REF可以获取此连接实例。用户定义了
add_connection(name="COM"), 则使用uut = lib.conn.COM可以获取此连接实例。
获取连接实例 uut 后, 可以使用实例的以下几种属性:
uut.open():打开连接. 需要说的是: 每次open()前, 会先调用close()方法。uut.close():关闭连接uut.send(): 向连接传递命令行.uut.buf:保存uut.send()语句发送后, 待测产品反馈的日志。uut.phrase:保存uut.send()语句发送后, 收到的expect字符串。uut.capture():对uut.buf进行解析, 获取想要的字符串片段。
需要强调的是:uut.send() 是传递命令行至待测产品UUT的唯一方式, 使用方法如下:
uut.send("python\r", expect=">>>", timeout=10)
对此语句的解释:通过 uut.send 发送命令行 python , 并带回车符 \r , 并期望在 timeout 的 10 秒钟内, 收到字符串 >>> 。
若收到, 此语句正常完成, 产品反馈的日志将以字符串形式保存在 uut.buf 中, 然后执行下一条语句。
若未收到字符串 >>>, 则触发异常(用户可以使用 try...except... 捕获此异常)。
需要说明的是:
uut.send()的expect可以接受列表list, 若expect为列表时, 当平台收到列表中的任意一元素时,uut.send()语句执行完成, 收到的元素保存在uut.phraseuut.send("dir\r", expect=[">", "#", "$"], timeout=60) log.debug(uut.phrase) if uut.phrase in [">", "#"]: pass if uut.phrase in ["$"]: raise Exception("Got '$', go to fail")
uut.send()的expect可以接受元组tuple, 若expect为元组时, , 当平台必须收到元组中的所有元素,uut.send()语句执行完成。uut.send("dir\r", expect=(">", "TEST PASSED"), timeout=60)
uut.send()前会自动清空uut.buf内容,uut.send()完成后, 收到的所有字符会自动保存在uut.buf。此例中uut.send()完成后, 若使用log.debug(uut.buf), 将在事件日志窗口打印出如下字符:python Python 3.7.8 (tags/v3.7.8:4b47a5b6ba, Jun 28 2020, 08:53:46) [MSC v.1916 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>>
uut.capture可以快速截取uut.buf中用户想要的字符串, 并支持正则表达, 其用法如下:# 语法说明 user_string = uut.capture(start_string, end_string="\n") # 例如:想要获取Python的版本(此例中, 版本为:3.7.8 ) version = uut.capture("Python", "(tags")
lib.ask_question()
lib.ask_question() 提供一种用户交互方法, 调用此接口函数后, 网页界面将弹出对话框, 用户可以在对话框应答一个问题, 并返回答案(字符串).
典型应用场景:弹出对话框, 要求用户输入产品的序列号:
ans = lib.ask_question("请输入序列号SERIAL: ", timeout=60 * 3)
答案会保存在 ans 中。
需要说明的是:lib.ask_question() 支持传入如下参数:
options: 备选答案, 是一个列表, 例如["12345", "678990"]。若传入, 则网页会弹出一个单项选择题对话框, 若不设置, 则弹出一个填空题对话框。image: 问题描述图片, 是一个字符串, 例如"demo\bee.jpg"。若传入, 则弹出的对话框会展示图片信息, 图片高度建议是320px。visible: 输入内容可视, 默认为True。若设置为False, 则用户输入内容显示为*号, 常用于密码输入等场景。multiple: 多选题, 默认为False。若设置为True, 则网页弹出一个多项选择题。当options未设置时,multiple无效。privilege: 插队, 默认为False。多Container工位提问, 遵循FIFO先进先出原则。若设置为True, 将插队至队列的第一位。timeout: 超时, 默认为3600秒。若在超时时间内, 用户未响应问题, 则触发异常。tips: 小提示, 默认为"", 可以增加一些提示性字符串。
lib.ask_questions()
此接口函数提供一个用户交互方法, 调用此函数后, 网页界面将弹出对话框, 用户可以在对话框同时应答多个问题, 并返回答案(列表).
使用示例:弹出对话框, 要求应答多个问题:
ans = lib.ask_questions(["请输入序列号SERIAL: ", "请输入UUTTYPE: ", "请输入员工工号:"], timeout=60 * 3)
答案将保存在 ans 中。
需要说明的是:lib.ask_questio() 支持传入如下参数:
image: 问题描述图片, 是一个字符串, 例如"demo\bee.jpg"。若传入, 则弹出的对话框会展示图片信息, 图片高度建议是320px。privilege: 插队, 默认为False。多Container工位提问, 遵循FIFO先进先出原则。若设置为True, 将插队至队列的第一位。timeout: 超时, 默认为3600秒。若在超时时间内, 用户未响应问题, 则触发异常。tips: 小提示, 默认为"", 可以增加一些提示性字符串。
需要强调的是: lib.ask_questions() 与 lib.ask_question() 共享同一个 FIFO队列 。
lib.set_display1/2/3/4/5/6()
lib.set_display1/2/3/4/5/6() 可以设置任意信息, 鼠标在container面板上悬停时将展示display1/2/3/4/5/6的内容.
lib.set_step_name()
lib.set_step_name() 设置当前测试项目名称, 若测试项FAIL, 测试记录会自动用此名称作为测试失败项, PASS则不记录。
使用示例:
lib.set_step_name("run cpu test")
lib.get_container_name()
lib.get_container_name() 返回当前的测试工位名称。
使用示例:在 FT:UUT00 上点击开始测试, 返回值为字符串 FT:UUT00
container_name = lib.get_container_name()
lib.add_test_data()
lib.add_test_data() 可以为产品做测试记录。
测试过程中, 使用此接口函数记录产品信息, 测试完成后, 根据测试结果成功或是失败, 自动记录一笔 PASS 或是 FAIL
lib.add_test_data(sernum=serial, uuttype=uuttype, area="FT")
需要强调的是: 此接口函数至少需要传入3个参数, 它们是: sernum 产品条码, uuttype 产品类型, area 测试工序名称。
需要说明的是:此接口函数还支持传入更多参数, 以便帮助用户记录更多信息, 它们是:
label1, label2, label3, label4, label5version1, version1, version3, version4, version5str1, str2, str3, str4, str5, str6
lib.get_mode()
lib.get_mode() 返回当前测试的模式, 值为 PRODUCT 或是 DEVELOP
mode = lib.get_mode()
lib.get_params()
lib.get_params() 返回 hostname.py 中当前工站的 add_params_data() 的值.
返回值是一个字典:
params = lib.get_params()
例: 如设置 add_params_data(ip="192.168.1.1", ip=2003), 则返回值为 {"host": "192.168.1.1", "port": 2003} 。
lib.start_test()
使用一个 container 启动其他 container 测试。
使用示例:
使用 lib.start_test("DEMO:UUT01") 启动 DEMO:UUT01 测试。
使用 lib.start_test(["DEMO:UUT01", "DEMO:UUT02"]) 连续启动多个 container 测试。
lib.stop_test()
使用一个 container 停止其他 container 测试。
使用示例:
使用 lib.stop_test("DEMO:UUT01") 停止 DEMO:UUT01 测试。
使用 lib.stop_test(["DEMO:UUT01", "DEMO:UUT02"]) 连续停止多个 container 测试。
需要说明的是: lib.stop_test() 仅对正在测试中的 container 产生作用.
lib.deposit_test()
使用一个 container 回收其他 container 测试。
使用示例:
使用 lib.deposit_test("DEMO:UUT01") 回收 DEMO:UUT01 测试。
使用 lib.deposit_test(["DEMO:UUT01", "DEMO:UUT02"]) 连续回收多个 container 测试。
需要说明的是: lib.deposit_test() 仅对已经测试完成(PASS/FAIL/STOP)的 container 产生作用.
lib.get_sequence_definition()
返回 sequence 实例, 用此实例编排测试序列, 测试过程中, 可以在 调试界面 的 STEP 窗口查看测试序列流程图。
假设测试代码中定义有如下函数:
def run_test():
log.debug("welcome to main sequence")
container_name = lib.get_container_name()
log.debug(container_name)
return
def run_test1(name):
uut = lib.get_uut(protocol="DUMMY")
log.debug("run test1: dir, name: {}".format(name)
uut.send("dir\r", expect=">", timeout=10)
time.sleep(1)
return
def run_test2():
uut = lib.conn.UUT
uut.open()
log.debug("run test2: cd")
uut.send("cd\r", expect=">", timeout=10)
return
def run_test3():
lib.add_test_data(sernum="1234567890", uuttype="DEMO", area="DEMO")
log.debug("run test3")
return
sequence 的基本使用示例:
def main_sequence():
seq = lib.get_sequence_definition()
seq.add_step(run_test, name="RUN TEST")
seq.add_step(run_test1, name="RUN TEST1", kws={"name": "gps test"})
seq.add_step(run_test2, name="RUN TEST2")
seq.add_step(run_test3, name="RUN TEST3")
return seq
注意:add_step() 后要跟函数或方法的名字, 免小括号()。
sequence 形式的代码编排, 为测试策略的实施提供了便利, 以下是当前支持的策略, 更多策略持续增加中。
通过设置
kws={"name": "gps test"}可以向函数或方法传递参数.
sequence定义传参:
seq.add_step(run_test1, name="RUN TEST1", kws={"name": "gps test"})
需要说明的是: 这里必须使用 kws, 不能使用 kwargs 或是其他关键字.
函数或方法接受传参:
def run_test1(name=""):
uut = lib.get_uut(protocol="DUMMY")
log.debug("run test1: dir, name: {}".format(name)
uut.send("dir\r", expect=">", timeout=10)
time.sleep(1)
return
需要说明的是: 函数或方法的入参需要这样定义: xxx=yyy .
通过设置
in_parallel=True可以实施平行测试策略。
包含 in_parallel 的step或是sequence, 会与下一个step或是sequence平行测试.
使用示例:
def main_sequence():
seq = lib.get_sequence_definition()
seq.add_step(run_test, name="RUN TEST")
seq.add_step(run_test1, name="RUN TEST1", in_parallel=True)
seq1 = seq.add_sequence("SUB SEQUENCER")
seq1.add_step(run_test2, name="RUN TEST2")
seq1.add_step(run_test3, name="RUN TEST3")
seq.add_step(run_test4, name="RUN TEST4")
return seq
3. 通过设置 cycle_time=60 * 5 可以实施 按时间循环测试 策略。
例子中 run_test2 每次测试完成后, 会检查累计消耗时间, 若小于 cycle_time , 将再一次测试。 但如果fail, 循环测试终止。
使用示例:
def main_sequence():
seq = lib.get_sequence_definition()
seq.add_step(run_test, name="RUN TEST")
seq.add_step(run_test1, name="RUN TEST1")
seq.add_step(run_test2, name="RUN TEST2", cycle_time=60 * 5)
seq.add_step(run_test3, name="RUN TEST3")
return seq
4. 通过设置 cycle_count=10 可以实施 按次数循环测试 策略。
例子中 run_test2 每次测试完成后, 会检查累计次数, 若小于 cycle_count, 将再执行一次测试, 但如果测试失败, 循环将终止。
使用示例:
def main_sequence():
seq = lib.get_sequence_definition()
seq.add_step(run_test, name="RUN TEST")
seq.add_step(run_test1, name="RUN TEST1")
seq.add_step(run_test2, name="RUN TEST2", cycle_count=10)
seq.add_step(run_test3, name="RUN TEST3")
return seq
需要说明的是: 当在一个 step 上同时使用 cycle_time 与 cycle_count 时, 仅 cycle_time 生效。
在
get_sequence_definition中设置finalize=True, 如果中途测试失败, 程序将自动执行最后一个step.
使用示例:
def main_sequence():
seq = lib.get_sequence_definition("SEQ", finalize=True)
seq.add_step(run_test, name="RUN TEST")
seq.add_step(run_test1, name="RUN TEST1")
seq.add_step(run_test2, name="RUN TEST2")
seq.add_step(run_test3, name="RUN TEST3")
return seq
本示例中, 如果中途测试失败, 程序将自动执行 run_test3 , 然后再停止测试.
lib.get_json_params()
返回当前项目下的JSON文件中的值, json的命名必须是 params.json ,
如当前项目为 demo, 则JSON文件的路径为 demo/params.json 。
其中, JSON内容示例如下:
{
"fct": [
{
"description": "it is fct description",
"name": "it is fct name",
"value": "123"
}
],
"lab": [
{
"description": "it is description",
"name": "hello",
"value": "world"
},
{
"description": "it is description2",
"name": "it is name2",
"value": "100"
}
]
}
若要获取 lab 中 name 为 hello 的值:
value = lib.get_json_params("lab", "hello")
返回字符串value的值是 world 。
lib.get_configuration()
在 hostname.py 中调用此接口函数, 可以更精细化定制用户界面。
使用示例:
from kunlun import lib
def main():
kl = lib.get_configuration()
station = kl.add_station("BST", "功能测试", recycle=False, image=r"demo\bee.jpg", dense=False)
station.add_sequence("project.sequence")
station.add_params_data(host="192.168.0.1")
for i in range(4):
container = station.add_container("UUT{:02d}".format(i))
container.add_params_data(ip="192.168.1.{}".format(i), test="hello world")
ctn.show_info_panel(col=4, row=2)
ctn.show_step_panel(col=4, row=2)
ctn.show_event_panel(col=4, row=2)
ctn.show_measure_panel(col=12, row=1)
ctn.add_connection(name="REF", protocol="DUMMY", col=8, row=2)
station = kl.add_station("BP2", "FT测试", recycle=False)
station.add_sequence("project.sequence")
station.add_params_data(host="192.168.0.1")
for i in range(4):
container = station.add_container("UUT{:02d}".format(i))
container.add_connection(name="UUT", protocol="DUMMY")
container.show_measure_panel()
需要说明的是: show_measure_panel() 与 show_measure_panel() 可以通过参数 col 与 row 改变窗口的大小, 以下是默认值:
container.show_step_panel(col=12, row=2)
container.show_measure_panel(col=12, row=2)
其中, col 的取值建议是: 4/8/12 , row 的取值建议是 1/2 .
lib.add_measure()
前置条件: 在 hostname.py 中使用 show_measure_panel() , 则Connection页面增加一个MEASURE窗口。
在测试代码中, 使用接口函数, 可以在MEASURE窗口增加一个measure项目, 示例如下:
result = lib.add_measure("TEST_MEASURE1", value=3, low=1, high=4)
或是使用 spec 作为参数:
result = lib.add_measure("TEST_MEASURE1", value=3, spec=[1, 4])
当measure检查通过时 result=True , 否则 result=False .
需要重点说明的是: 参数 value , low , high 或是 spec 的值可以为字符串数字, 接口函数将会将字符串数字自动转为 float 型.
双击measure项目, 可以得到该项目的线性图。
lib.add_xlsx_measure()
lib.add_xlsx_measure(sheet, name, value) 是 lib.add_measure() 的封装,
它自动调用项目下的文件 demo/measure.xlsx 中的 low 与 high 值, 然后调用 lib.add_measure() 进行对比.
在测试代码中, 使用接口函数, 可以在MEASURE窗口增加一个measure项目, 示例如下:
result = lib.add_xlsx_measure("pcba", "meas1", 30)
当measure检查通过时 result=True , 否则 result=False .
demo/measure.xlsx 的格式如下:
name |
lower |
upper |
desc |
|---|---|---|---|
meas1 |
20 |
50 |
rf |
meas2 |
40 |
78.9 |
gps |
meas3 |
-35 |
35.9 |
ground |
假设XLSX当前的Sheet名为 pcba , 待检查的指标名为 meas1 , 实际测量值为 30 。
调用 lib.add_xlsx_measure("pcba", "meas1", 30), XLSX文件中 meas1 的lower(指标下限)为 20 ,
upper(指标上限)为 50 , 因为 20<=30<=50 , 所以指标检查通过。