
Security News
NVD Concedes Inability to Keep Pace with Surging CVE Disclosures in 2025
Security experts warn that recent classification changes obscure the true scope of the NVD backlog as CVE volume hits all-time highs.
为什么已经有了rock4automation的自动化测试框架的项目,还要另起一个rtsf项目,并且rtsf中使用的技术,rock4automation项目中已经涵盖?
因为,它存在的痛点很明显:
而rtsf(rock4 test service framework)项目的初衷:
我这里已经完成了几个rtsf+的项目,供大家参考和使用:
其他可接入的方案:
等等
测试用例模型,计划扩展为, yaml, xml, excel三种,目前已扩展的只有yaml测试用例模型
pip install rtsf
rtsf提供测试执行、报告、日志的基本功能
注意: 其内在逻辑,其实是,先加载api和suite,以dict形式存储在内置变量中,然后,加载测试集的用例,如果测试用例使用了api则合并,如果测试用例使用了suite则扩展。
# test.yaml
- project:
name: demo project
module: the module name of testing project
- case:
name: case 1
- case:
name: case call api 1
api: test1_api()
- case:
name: case call suite
api: test_suite(1, 2)
# test_api.yaml
- api:
def: test1_api()
- api:
def: test2_api($arg1, $arg2)
suite的用例跟 case差别不大,主要的是,在project中,添加def关键字,定义引入suite的函数入口
# test_suite.yaml
- project:
def: test_suite($arg1, $arg2)
- case:
name: suite 1
- case:
name: suite call api 2
api: test2_api($arg1, $arg2)
变量和函数的替换,参照了httprunner项目的格式 该格式取代了我的rock4automation项目中的, #var# 等替换规则
使用默认Runner类执行规则,执行test.yaml测试用例
from rtsf.p_executer import TestRunner, Runner
runner = TestRunner(runner = Runner).run(r'C:\xxx\xxx\test.yaml')
runner.gen_html_report()
编写一个测试用例文件,如 example_1.yaml
# example_1.yaml
- project:
name: demo project
module: test baidu
- case:
name: www.baidu.com
example_1执行后的报告:
代码,参见项目目录examples/example_1
如下,创建三个文件,example_2.yaml, username_password.csv, devices.csv
# example_2.yaml
- project:
name: demo project
module: test baidu
data:
- csv: devices.csv
by: Random
- csv: username_password.csv
- case:
name: www.baidu.com-$username-$password-$devices
# username_password.csv
username,password
15312341230,1234567890
15312341231,1234567891
# devices.csv
devices
android-0
android-1
android-2
数据驱动,其实很简单,在yaml的测试用例中,在project块,添加data关键字。
data关键字,以列表形式存在,每个列表项是一个字典,由两个key组成(csv, by)。跟loadrunner中参数化数据一样,csv第一行定义变量,第二行及以下行定义数据驱动的变量值
example_2执行后的报告,如下, 跑了6条用例,是username_password.csv和devices.csv里边参数的笛卡儿积,username_password默认是顺序,devices是随机。
代码,参见项目目录examples/example_2
首先, 我们设计我们的yaml用例, 比如,在上面的例子中,加入了几个关键字, responsible, tester, demotest, demoverify
# example_3.yaml
- project:
name: demo project
module: test baidu
- case:
name: demo test
responsible: your name
testser: other name
demotest: ${add(1, 2)}
demoverify: ${_is(3)}
- case:
name: demo test2
responsible: your name
testser: other name
demotest: ${mod(1, 2)}
demoverify: ${_is(3)}
- case:
name: demo test3
responsible: your name
testser: other name
demotest: ${mod(1, 0)}
demoverify: ${_is(3)}
然后,重写Runner, 对上面关键字进行功能设置, 重写 Runner.run_test的过程,是使用rtsf的主要工作
注意: 重写的时候,第一个参数,是单个case,不是所有case,只需要写一个case的执行逻辑
# DemoRunner.py
# encoding:utf-8
from rtsf.p_executer import TestRunner, Runner
def test_add(x, y):
global result
result = x+y
def test_mod(x, y):
global result
result = x%y
def verify_is(x):
return result == x
class DemoRunner(Runner):
def __init__(self):
''' 继承Runner
self._default_devices --> list,分布式设备标识。 默认 值 [""],表示本机
self._default_drivers --》 list, 分布式driver标识与driver键值对。 默认值 [("",None)], 表示本机驱动
self.parser --> TestCaseParser实例,用于解析用例
self.tracers --> 每一台分布式设备初始化的Tracer实例,用于记录日志和生成报告
self.proj_info --> 记录了用例的项目信息
'''
super(DemoRunner,self).__init__()
def run_test(self, testcase_dict, variables, driver_map):
''' 重写 run_test,有三个参数
@parm testcase_dict: 单条测试用例
@param variables: dict; 用例采用数据驱动的情况下,variables是csv文件变量的笛卡儿积;默认情况下值是 {}
@param driver_map: tuple; (唯一标识, driver or module or obj); 默认情况下的值是("",None),该参数适用于selenium的grid有多个 driver的情况
'''
# rtsf 遍历 self._default_drivers, 传给 driver_map 这里fn = '' driver=None
fn, driver = driver_map
# 获取 fn 的跟踪对象, 用于记录日志 和 报告
fn_logger = self.tracers[fn]
# 获取用例解析对象
parser = self.parser
# 绑定测试用例关键字
yaml_keys = {"add": test_add, "mod": test_mod, '_is': verify_is}
parser.bind_functions(yaml_keys)
# 更新传入的变量
parser.update_binded_variables(variables)
# 获取用例名字
case_name = testcase_dict.get("name")
# parser.eval_content_with_bind_actions 用于解析 字段中的变量和函数, 如: 引用函数: ${function_str} 引用变量: $variable_str
case_name = parser.eval_content_with_bind_actions(case_name)
try:
# fn_logger 可以记录报告,使用: start, section, step, normal, ok, fail, error, stop
# start 用于 开始记录报告; stop 用于结束报告记录
fn_logger.start(self.proj_info["module"], # yaml case中 module
case_name, # yaml case中 用例名臣
testcase_dict.get("responsible",u"administrator"), # yaml case中responsible定义的责任人名称
testcase_dict.get("tester",u"administrator"), # yaml case中tester定义的测试人名称
)
# fn_logger 可以使用了logging, 记录日志,使用: log_debug, log_info, log_warning, log_error, log_critical
fn_logger.log_debug(u"===== run_test\n\t{}".format(testcase_dict))
fn_logger.section(u"------------starting test")
# 获取demotest
demotest = testcase_dict.get("demotest")
fn_logger.step("got demotest: %s" %demotest)
parser.eval_content_with_bind_actions(demotest)
fn_logger.normal(u"eval demotest. finish")
# 获取demoverify
demoverify = testcase_dict.get("demoverify")
fn_logger.step("got demoverify: %s" %demoverify)
if parser.eval_content_with_bind_actions(demoverify):
fn_logger.ok('verify is ok')
else:
fn_logger.fail('verify is fail')
fn_logger.normal(u"eval demoverify. finish")
except Exception as e:
fn_logger.error(e)
fn_logger.stop()
最后,我们设置runner参数为 DemoRunner, 执行我们自定义的用例逻辑
# example_3.py
# encoding:utf-8
from rtsf.p_executer import TestRunner, Runner
from DemoRunner import DemoRunner
runner = TestRunner(runner = DemoRunner).run(r'example_3.yaml')
runner.gen_html_report()
example_3执行后的报告,如下,跑了3条用例,1条通过,1条失败,1条报错
代码,参见项目目录examples/example_3
使用上述的DemoRunner,我们设计下 分层的用例,创建如下三个文件, 文件名可以自定义,路径要正确
# ./dependencies/api/test_api.yaml
- api:
def: add_api($arg1, $arg2, $exp)
demotest: ${add($arg1, $arg2)}
demoverify: ${_is($exp)}
- api:
def: mod_api($arg1, $arg2, $exp)
demotest: ${mod($arg1, $arg2)}
demoverify: ${_is($exp)}
# ./dependencies/suite/test_suite.yaml
- project:
def: suite_test()
- case:
name: suite 1
api: add_api(1, 2, 3)
- case:
name: suite 2
api: mod_api(2, 2, 0)
- case:
name: suite 3
demotest: ${add(1, 2)}
demoverify: ${_is(3)}
# ./example_4.yaml
- project:
name: demo project
module: a demo test
- case:
name: case 0
suite: suite_test()
- case:
name: case 1
api: add_api(1, 2, 100)
- case:
name: case 2
api: mod_api(1, 2, 100)
- case:
name: case 3
demotest: ${add(1, 2)}
demoverify: ${_is(3)}
example_4执行后的报告,如下,跑了6条用例,suite中3条通过,case的3条中,2条失败,1条成功
代码,参见项目目录examples/example_4
在上述DemoRunner重写 Runner.run_test的过程中,我们定义了三个yaml函数: add, mod, _is, 映射到内置函数, test_add test_mod verify_is
rtsf 提供了另一种更简单的方法
# preference.py
#encoding:utf-8
def add(x, y):
global result
result = x+y
def mod(x, y):
global result
result = x%y
def _is(x):
return result == x
...
# 绑定测试用例关键字
# yaml_keys = {"add": test_add, "mod": test_mod, 'is': verify_is}
# parser.bind_functions(yaml_keys)
...
执行结果,同 example_4
代码,参见项目目录examples/example_5
基于约定大于配置的原则,使用rsft构建自己的自动化测试框架
,rtsf系列框架,约定的case基本结构 如下:
- project:
name:
module:
data:
- case:
name:
responsible:
tester:
glob_var:
glob_regx:
pre_command:
steps:
post_command:
verify:
执行顺序 pre_command(List) -> steps(List) -> post_command(List) -> verify(List)
preject定义测试集信息
project字段 | 描述 | 类型 |
---|---|---|
name | 项目名称或待测系统名称(必填) | 字符串 |
module | 测试集或功能模块名称(必填) | 字符串 |
data | 数据驱动,引用的数据(选填) | 列表 |
case定义测试用例
case字段 | 描述 | 类型 |
---|---|---|
name | 描述 用例 (必填),唯一性(必填) | 字符串 |
responsible | 用例责任人或者编写人(选填) | 字符串 |
tester | 用例执行者或者测试人(选填) | 字符串 |
glob_var | 全局变量(选填) | 字典 |
glob_regx | 全局正则(选填) | 字典 |
pre_command | 测试的前置步骤或钩子(选填) | 列表 |
steps | 测试步骤 (必填) | 列表 |
post_command | 测试的后置步骤或钩子(选填) | 列表 |
verify | 校验 (选填) | 列表 |
FAQs
a test service framework
We found that rtsf demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Security experts warn that recent classification changes obscure the true scope of the NVD backlog as CVE volume hits all-time highs.
Security Fundamentals
Attackers use obfuscation to hide malware in open source packages. Learn how to spot these techniques across npm, PyPI, Maven, and more.
Security News
Join Socket for exclusive networking events, rooftop gatherings, and one-on-one meetings during BSidesSF and RSA 2025 in San Francisco.