HttpRunner3源码分析(1) - cli.py

HttpRunner3和2的区别挺大,3的底层使用pytest,2的底层是unittest.

在兼容json和yaml格式测试用例的前提下,作者更鼓励使用写代码来接入.

HttpRunner3源码分析(1) - cli.py_第1张图片

具体可以看这篇文章分析对比


入口文件cli.py

概要导图:

HttpRunner3源码分析(1) - cli.py_第2张图片

详解

命令行驱动的库很容易找到入口地址. 在这个文件内,主要有以下方法:

  • 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_contentDict格式.

    最后会是合法的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库。


Python中最好用的命令行解析工具:argparse

你可能感兴趣的:(python)