HttpRunner3和2的区别挺大,3的底层使用pytest,2的底层是unittest.
在兼容json和yaml格式测试用例的前提下,作者更鼓励使用写代码来接入.
具体可以看这篇文章分析对比
入口文件cli.py
概要导图:
image.png
详解
命令行驱动的库很容易找到入口地址. 在这个文件内,主要有以下方法:
- main(), 使用argparse接收用户输入的命令,决定走哪个方法,关键代码
输入httprunner后,接下来的单词:
if sys.argv[1] == "run":
sys.exit(main_run(extra_args))
elif sys.argv[1] == "startproject":
main_scaffold(args)
elif sys.argv[1] == "har2case":
main_har2case(args)
elif sys.argv[1] == "make":
main_make(args.testcase_path)
- main_run()方法
首先判断httprunner run xxx的路径xxx在系统里是否存在.
然后47行,testcase_path_list = main_make(tests_path_list)会调用make.py里的main_make()方法,把json,yml等格式的文件,转化为pytest能执行的.py文件. (make.py文件有600多行,主要就是将json,yml文件转为pytest格式.)
在make.py的528行,test_content = load_test_file(test_file),导出的文件test_content是Dict格式.
最后会是合法的testcase目录或者文件,调用pytest.main('用例列表')
-
main_har2case() 将har文件转为测试文件,默认转为pytest使用的Text_xxx.py
-
main_scaffold()创建一个httprunner标准工程文件夹
-
cli.py里的其他内容,就是定义har2case,hrun等缩写命令
测试文件转换
代码里分别用yaml.load()和json.load()将yml和json文件转为字典Dict格式
读取yml文件原始内容是:
config:
name: "request methods testcase: reference testcase"
variables:
foo1: testsuite_config_bar1
expect_foo1: testsuite_config_bar1
expect_foo2: config_bar2
base_url: "https://postman-echo.com"
verify: False
teststeps:
-
name: request with functions
variables:
foo1: testcase_ref_bar1
expect_foo1: testcase_ref_bar1
testcase: testcases/demo_testcase_request.yml
export:
- foo3
-
name: post form data
variables:
foo1: bar1
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "application/x-www-form-urlencoded"
data: "foo1=$foo1&foo2=$foo3"
validate:
- eq: ["status_code", 200]
- eq: ["body.form.foo1", "bar1"]
- eq: ["body.form.foo2", "bar21"]
框架转换后的格式为:
{
'config': {
'name': 'request methods testcase: reference testcase',
'variables': {
'foo1': 'testsuite_config_bar1',
'expect_foo1': 'testsuite_config_bar1',
'expect_foo2': 'config_bar2'
},
'base_url': 'https://postman-echo.com',
'verify': False
},
'teststeps': [{
'name': 'request with functions',
'variables': {
'foo1': 'testcase_ref_bar1',
'expect_foo1': 'testcase_ref_bar1'
},
'testcase': 'testcases/demo_testcase_request.yml',
'export': ['foo3']
}, {
'name': 'post form data',
'variables': {
'foo1': 'bar1'
},
'request': {
'method': 'POST',
'url': '/post',
'headers': {
'User-Agent': 'HttpRunner/${get_httprunner_version()}',
'Content-Type': 'application/x-www-form-urlencoded'
},
'data': 'foo1=$foo1&foo2=$foo3'
},
'validate': [{
'eq': ['status_code', 200]
}, {
'eq': ['body.form.foo1', 'bar1']
}, {
'eq': ['body.form.foo2', 'bar21']
}]
}]
}
源码优点总结||小技巧
``其他方法时,统一从根目录开始,而不是当前文件的相对目录
from httprunner.ext.har2case import init_har2case_parser, main_har2case
from httprunner.make import init_make_parser, main_make
from httprunner.scaffold import init_parser_scaffold, main_scaffold
from httprunner.utils import init_sentry_sdk
判断文件名后缀if test_file.lower().endswith("_test.py"):
导入文件内容等操作,统一封装在loader.py文件里.
loader.py里导入测试用例时,用Pydantic库来验证数据类型, testcase_obj = TestCase.parse_obj(testcase)将对象加载到模型中,如果对象不是字典则报错.
使用os.sep.join()消除linux和windows平台的文件路径差异
使用pydantic定义类的数据类型
使用parser.parse_known_args() 接收额外参数
if len(sys.argv) >= 2 and sys.argv[1] in ["run", "locusts","define"]:
args, extra_args = parser.parse_known_args() # 接收额外参数
# 执行 python3 test.py run tt01/testcases/login_battle_test.py
# args is : Namespace(version=False)
# extra_args is : ['tt01/testcases/login_battle_test.py']
else:
args = parser.parse_args()
# 执行 python3 test.py har2case tt01/testcases/login_battle_test.py
# args is Namespace(exclude=None, filter=None, har_source_file='tt01/testcases/login_battle_test.py', to_json=False, to_yaml=False, version=False)
将参数里的文件路径和命令参数分开保存
for item in extra_args:
if not os.path.exists(item):
# item is not file/folder path
extra_args_new.append(item)
else:
# item is file/folder path
tests_path_list.append(item)
httprunner框架在单纯处理最后发起自动化交易请求之外,有较大的精力需要去处理测试用例文件的问题,例如判断当前文件路径,文件格式转换,
pytest: error: unrecognized arguments: --html=report.html报错是因为需要额外安装 pip install pytest-html。
pytest-html 是pytest的插件,不属于pytest库。
网友评论