接口函数
模拟键盘操作
可以发送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的绝对路径, WIN10下是 C:\kunlun-data
, LINUX下是 ~/kunlun-data
。
lib.SCRIPT_PATH
获取当前开发模式的测试程序所在的绝对路径。
WIN10下是:
C:\kunlun-data\kunlun_scripts
.LINUX下是:
~/kunlun-data/kunlun_scripts
.
lib.LOG_PATH
获取当前测试的日志所在的绝对路径+当前测试时间戳, 它并不是一个路径, 它的作用是: 用户可以拷贝自定义的文件到日志的路径下, 方便在Test Data页面下载。
例如WIN10下是: C:/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.phrase
uut.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, label5
version1, version1, version3, version4, version5
str1, 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")
container.add_connection(name="UUT", protocol="DUMMY")
container.show_measure_panel()
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
, 所以指标检查通过。