diff --git a/development/dev-api/index.html b/development/dev-api/index.html index 51333588..9ff1b2cb 100644 --- a/development/dev-api/index.html +++ b/development/dev-api/index.html @@ -582,52 +582,45 @@ - - - -
HttpRunner 除了作为命令行工具使用外,还可以作为软件包集成到你自己的项目中。
简单来说,HttpRunner 提供了运行 YAML/JSON 格式测试用例的能力,并能返回详细的测试结果信息。
HttpRunner 以 类(class)
的形式对外提供调用支持,类名为HttpRunner
,导入方式如下:
HttpRunner 以 类(class)
的形式对外提供调用支持,类名为HttpRunner
。使用方式如下:
from httprunner.api import HttpRunner + +runner = HttpRunner( + failfast=True, + save_tests=True, + log_level="INFO", + log_file="test.log" +) +summary = runner.run(path_or_tests)
HttpRunner
内部用于驱动测试执行的是 unittest.TextTestRunner
,在初始化 HttpRunner
时可以使用 TextTestRunner 的所有可用参数(详情可阅读官方文档)。除此之外,HttpRunner
还额外支持一个参数,http_client_session
,可用于指定不同的客户端类型。
通常情况下,初始化 HttpRunner
时常用的参数有如下几个:
通常情况下,初始化 HttpRunner
时的参数有如下几个:
resultclass
: HtmlTestResult/TextTestResult,默认值为 HtmlTestResultfailfast
: 设置为 True 时,测试在首次遇到错误或失败时会停止运行;默认值为 Falsehttp_client_session
: 传入requests.Session()
时进行自动化测试(默认),传入locust.client.Session()
时进行性能测试failfast
(可选): 设置为 True 时,测试在首次遇到错误或失败时会停止运行;默认值为 Falsesave_tests
(可选): 设置为 True 时,会将运行过程中的状态(loaded/parsed/summary)保存为 JSON 文件,存储于 logs 目录下;默认为 Falselog_level
(可选): 设置日志级别,默认为 "INFO"log_file
(可选): 设置日志文件路径,指定后将同时输出日志文件;默认不输出日志文件例如,如需初始化 HttpRunner
时设置 failfast
为 False,初始化方式如下所示:
from httprunner.api import HttpRunner - -runner = HttpRunner(failfast=False) -
在 HttpRunner
中,对外提供了两个方法:
在 HttpRunner
中,对外提供了一个 run
方法,用于运行测试用例。
run 方法有三个参数:
run
: 运行测试用例gen_html_report
: 生成 HTML 测试报告path_or_tests
(必传): 指定要运行的测试用例;支持传入两类参数在 HttpRunner
中,对外提供了一个属性:
summary
: 测试执行结果该属性需要在调用 run
方法后获取。
HttpRunner
的 run 方法有三个参数:
path_or_testcases
: 指定要运行的测试用例;支持传入两类参数,YAML/JSON 格式测试用例文件路径,或者标准的测试用例结构体;dot_env_path
(可选): 指定加载环境变量文件(.env)的路径,默认值为当前工作目录(PWD)中的 .env
文件mapping
(可选): 变量映射,可用于对传入测试用例中的变量进行覆盖替换。指定测试用例文件路径支持三种形式:
除了传入测试用例文件路径,还可以直接传入标准的测试用例结构体。
以 demo-quickstart-2.yml 为例,对应的数据结构体如下所示:
[ @@ -1041,10 +1022,9 @@其中,
env
对应的是.env
文件中的环境变量,debugtalk
对应的是debugtalk.py
文件中定义的变量和函数,def-api
对应的是api
文件夹下定义的接口描述,def-testcase
对应的是testcases
文件夹下定义的测试用例。通过传入标准的测试用例结构体执行测试时,传入的数据应包含所有信息,包括
-debugtalk.py
、.env
、依赖的 api 和 测试用例等;因此也无需再使用dot_env_path
和mapping
参数,所有信息都要通过refs
传入。返回详细测试结果数据¶
-运行完成后,通过
-summary
属性可获取详尽的运行结果数据。# get result summary -summary = runner.summary +返回详细测试结果数据¶
+运行完成后,通过
+run()
方法的返回结果可获取详尽的运行结果数据。@@ -1162,17 +1142,25 @@summary = runner.run(path_or_tests)生成 HTML 测试报告¶
-如需生成 HTML 测试报告,可调用
-gen_html_report
方法。# generate html report -runner.gen_html_report( - html_report_name="demo", - html_report_template="/path/to/custom_report_template" -) +如需生成 HTML 测试报告,可调用
+report.render_html_report
方法。+from httprunner import report -# => reports/demo/demo-1532078874.html +report_path = report.render_html_report( + summary, + report_template="/path/to/custom_report_template", + report_dir="/path/to/reports_dir", + report_file="/path/to/report_file_path" +)+
render_html_report()
的参数有四个:+
- summary(必传): 测试运行结果汇总数据
+- report_template(可选): 指定自定义的 HTML 报告模板,模板必须采用 Jinja2 的格式
+- report_dir(可选): 指定生成报告的文件夹路径
+- report_file(可选): 指定生成报告的文件路径,该参数的优先级高于 report_dir
+关于测试报告的详细内容,请查看测试报告部分。
diff --git a/search/search_index.json b/search/search_index.json index 0dd0653d..2ca52bc0 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"HttpRunner \u662f\u4e00\u6b3e\u9762\u5411 HTTP(S) \u534f\u8bae\u7684\u901a\u7528\u6d4b\u8bd5\u6846\u67b6\uff0c\u53ea\u9700\u7f16\u5199\u7ef4\u62a4\u4e00\u4efd YAML/JSON \u811a\u672c\uff0c\u5373\u53ef\u5b9e\u73b0\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u6027\u80fd\u6d4b\u8bd5\u3001\u7ebf\u4e0a\u76d1\u63a7\u3001\u6301\u7eed\u96c6\u6210\u7b49\u591a\u79cd\u6d4b\u8bd5\u9700\u6c42\u3002 \u6b64\u6587\u6863\u9002\u7528\u4e8e\u5168\u65b0\u53d1\u5e03\u7684 HttpRunner 2.x \u7248\u672c\uff0c 1.x \u7248\u672c\u7684\u4f7f\u7528\u6587\u6863\u8bf7\u67e5\u770b \u5386\u53f2\u94fe\u63a5 \u3002 \u8bbe\u8ba1\u7406\u5ff5 \u00b6 \u5145\u5206\u590d\u7528\u4f18\u79c0\u7684\u5f00\u6e90\u9879\u76ee\uff0c\u4e0d\u8ffd\u6c42\u91cd\u590d\u9020\u8f6e\u5b50\uff0c\u800c\u662f\u5c06\u5f3a\u5927\u7684\u8f6e\u5b50\u7ec4\u88c5\u6210\u6218\u8f66 \u9075\u5faa \u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e \u7684\u51c6\u5219\uff0c\u5728\u6846\u67b6\u529f\u80fd\u4e2d\u878d\u5165\u81ea\u52a8\u5316\u6d4b\u8bd5\u6700\u4f73\u5de5\u7a0b\u5b9e\u8df5 \u8ffd\u6c42\u6295\u5165\u4ea7\u51fa\u6bd4\uff0c\u4e00\u4efd\u6295\u5165\u5373\u53ef\u5b9e\u73b0\u591a\u79cd\u6d4b\u8bd5\u9700\u6c42 \u6838\u5fc3\u7279\u6027 \u00b6 \u7ee7\u627f Requests \u7684\u5168\u90e8\u7279\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0 HTTP(S) \u7684\u5404\u79cd\u6d4b\u8bd5\u9700\u6c42 \u91c7\u7528 YAML/JSON \u7684\u5f62\u5f0f\u63cf\u8ff0\u6d4b\u8bd5\u573a\u666f\uff0c\u4fdd\u969c\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u7684\u7edf\u4e00\u6027\u548c\u53ef\u7ef4\u62a4\u6027 \u501f\u52a9\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\uff0c\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u8f7b\u677e\u5b9e\u73b0\u590d\u6742\u7684\u52a8\u6001\u8ba1\u7b97\u903b\u8f91 \u652f\u6301\u5b8c\u5584\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff0c\u5145\u5206\u5b9e\u73b0\u6d4b\u8bd5\u7528\u4f8b\u7684\u590d\u7528 \u6d4b\u8bd5\u524d\u540e\u652f\u6301\u5b8c\u5584\u7684 hook \u673a\u5236 \u54cd\u5e94\u7ed3\u679c\u652f\u6301\u4e30\u5bcc\u7684\u6821\u9a8c\u673a\u5236 \u57fa\u4e8e HAR \u5b9e\u73b0\u63a5\u53e3\u5f55\u5236\u548c\u7528\u4f8b\u751f\u6210\u529f\u80fd\uff08 har2case \uff09 \u7ed3\u5408 Locust \u6846\u67b6\uff0c\u65e0\u9700\u989d\u5916\u7684\u5de5\u4f5c\u5373\u53ef\u5b9e\u73b0\u5206\u5e03\u5f0f\u6027\u80fd\u6d4b\u8bd5 \u6267\u884c\u65b9\u5f0f\u91c7\u7528 CLI \u8c03\u7528\uff0c\u53ef\u4e0e Jenkins \u7b49\u6301\u7eed\u96c6\u6210\u5de5\u5177\u5b8c\u7f8e\u7ed3\u5408 \u6d4b\u8bd5\u7ed3\u679c\u7edf\u8ba1\u62a5\u544a\u7b80\u6d01\u6e05\u6670\uff0c\u9644\u5e26\u8be6\u5c3d\u7edf\u8ba1\u4fe1\u606f\u548c\u65e5\u5fd7\u8bb0\u5f55 \u6781\u5f3a\u7684\u53ef\u6269\u5c55\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0\u4e8c\u6b21\u5f00\u53d1\u548c Web \u5e73\u53f0\u5316 \u66f4\u591a\u4fe1\u606f \u00b6 \u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"\u4ecb\u7ecd"},{"location":"#_1","text":"\u5145\u5206\u590d\u7528\u4f18\u79c0\u7684\u5f00\u6e90\u9879\u76ee\uff0c\u4e0d\u8ffd\u6c42\u91cd\u590d\u9020\u8f6e\u5b50\uff0c\u800c\u662f\u5c06\u5f3a\u5927\u7684\u8f6e\u5b50\u7ec4\u88c5\u6210\u6218\u8f66 \u9075\u5faa \u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e \u7684\u51c6\u5219\uff0c\u5728\u6846\u67b6\u529f\u80fd\u4e2d\u878d\u5165\u81ea\u52a8\u5316\u6d4b\u8bd5\u6700\u4f73\u5de5\u7a0b\u5b9e\u8df5 \u8ffd\u6c42\u6295\u5165\u4ea7\u51fa\u6bd4\uff0c\u4e00\u4efd\u6295\u5165\u5373\u53ef\u5b9e\u73b0\u591a\u79cd\u6d4b\u8bd5\u9700\u6c42","title":"\u8bbe\u8ba1\u7406\u5ff5"},{"location":"#_2","text":"\u7ee7\u627f Requests \u7684\u5168\u90e8\u7279\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0 HTTP(S) \u7684\u5404\u79cd\u6d4b\u8bd5\u9700\u6c42 \u91c7\u7528 YAML/JSON \u7684\u5f62\u5f0f\u63cf\u8ff0\u6d4b\u8bd5\u573a\u666f\uff0c\u4fdd\u969c\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u7684\u7edf\u4e00\u6027\u548c\u53ef\u7ef4\u62a4\u6027 \u501f\u52a9\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\uff0c\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u8f7b\u677e\u5b9e\u73b0\u590d\u6742\u7684\u52a8\u6001\u8ba1\u7b97\u903b\u8f91 \u652f\u6301\u5b8c\u5584\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff0c\u5145\u5206\u5b9e\u73b0\u6d4b\u8bd5\u7528\u4f8b\u7684\u590d\u7528 \u6d4b\u8bd5\u524d\u540e\u652f\u6301\u5b8c\u5584\u7684 hook \u673a\u5236 \u54cd\u5e94\u7ed3\u679c\u652f\u6301\u4e30\u5bcc\u7684\u6821\u9a8c\u673a\u5236 \u57fa\u4e8e HAR \u5b9e\u73b0\u63a5\u53e3\u5f55\u5236\u548c\u7528\u4f8b\u751f\u6210\u529f\u80fd\uff08 har2case \uff09 \u7ed3\u5408 Locust \u6846\u67b6\uff0c\u65e0\u9700\u989d\u5916\u7684\u5de5\u4f5c\u5373\u53ef\u5b9e\u73b0\u5206\u5e03\u5f0f\u6027\u80fd\u6d4b\u8bd5 \u6267\u884c\u65b9\u5f0f\u91c7\u7528 CLI \u8c03\u7528\uff0c\u53ef\u4e0e Jenkins \u7b49\u6301\u7eed\u96c6\u6210\u5de5\u5177\u5b8c\u7f8e\u7ed3\u5408 \u6d4b\u8bd5\u7ed3\u679c\u7edf\u8ba1\u62a5\u544a\u7b80\u6d01\u6e05\u6670\uff0c\u9644\u5e26\u8be6\u5c3d\u7edf\u8ba1\u4fe1\u606f\u548c\u65e5\u5fd7\u8bb0\u5f55 \u6781\u5f3a\u7684\u53ef\u6269\u5c55\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0\u4e8c\u6b21\u5f00\u53d1\u548c Web \u5e73\u53f0\u5316","title":"\u6838\u5fc3\u7279\u6027"},{"location":"#_3","text":"\u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"\u66f4\u591a\u4fe1\u606f"},{"location":"CHANGELOG/","text":"Release History \u00b6 2.3.2 (2019-11-01) \u00b6 Changed make render_html_report separate with HttpRunner().run_tests() --report-file : specify report file path, this has higher priority than specifying report dir. remove summary property from HttpRunner 2.3.1 (2019-10-28) \u00b6 Fixed fix locusts entry configuration Changed update PyPi classifiers 2.3.0 (2019-10-27) \u00b6 Added feat: implement plugin system prototype, make locusts as plugin test: add Python 3.8 to Travis-CI feat: add __main__.py , python -m httprunner can be used to hrun tests Changed update dependency versions in pyproject.toml rename folder, httprunner/templates => httprunner/static log httprunner version before running tests remove unused import & code Fixed fix #707: duration stat error in multiple testsuites 2.2.6 (2019-09-18) \u00b6 Added feat: config variables support parsing from function feat: support jsonpath to parse json response #679 feat: generate html report with specified report file #704 Changed remove unused import adjust code format Fixed fix: dev-rules link 404 2.2.5 (2019-07-28) \u00b6 Added log HttpRunner version when initializing Fixed fix #658: sys.exit 1 if any testcase failed fix ModuleNotFoundError in debugging mode if httprunner uninstalled 2.2.4 (2019-07-18) \u00b6 Changed replace pipenv & setup.py with poetry drop support for Python 3.4 as it was EOL on 2019-03-16 relocate debugging scripts, move from main-debug.py to httprunner.cli Fixed fix #574: delete unnecessary code fix #551: raise if times is not digit fix #572: tests_def_mapping[\"testcases\"] typo error 2.2.3 (2019-06-30) \u00b6 Fixed fix yaml FullLoader AttributeError when PyYAML version < 5.1 2.2.2 (2019-06-26) \u00b6 Changed extract is used to replace output when passing former teststep's (as a testcase) export value to next teststep export is used to replace output in testcase config 2.2.1 (2019-06-25) \u00b6 Added add demo api/testcase/testsuite to new created scaffold project update default .gitignore of new created scaffold project add demo content to debugtalk.py / .env of new created scaffold project Fixed fix extend with testcase reference in format version 2 fix ImportError when locustio is not installed fix YAMLLoadWarning by specify yaml loader 2.2.0 (2019-06-24) \u00b6 Added support testcase/testsuite in format version 2 Fixed add wheel in dev packages fix exception when teststep name reference former extracted variable 2.1.3 (2019-04-24) \u00b6 Fixed replace eval mechanism with builtins to prevent security vulnerabilities ImportError for builtins in Python2.7 2.1.2 (2019-04-17) \u00b6 Added support new variable notation ${var} use \\$\\$ to escape \\$ notation add Python 3.7 for travis CI Fixed match duplicate variable/function in single raw string escape '{' and '}' notation in raw string print_info: TypeError when value is None display api name when running api as testcase 2.1.1 (2019-04-11) \u00b6 Changed refactor upload files mechanism with requests-toolbelt : simplify usage syntax, detect mimetype with filetype . support upload multiple fields. 2.1.0 (2019-04-10) \u00b6 Added implement json dump Python objects when save tests implement lazy parser remove project_mapping from parse_tests result Fixed reference output variables pass output variables between testcases 2.0.6 (2019-03-18) \u00b6 Added create .gitignore file when initializing new project Fixed fix CSV relative path detection fix current validators displaying the former one when they are empty 2.0.5 (2019-03-04) \u00b6 Added implement method to get variables and output Fixed fix xss in response json 2.0.4 (2019-02-28) \u00b6 Fixed fix verify priority with nested testcase fix function in config variables called multiple times dump loaded tests when running tests_mapping directly 2.0.3 (2019-02-24) \u00b6 Fixed fix verify priority: teststep > config fix Chinese charactor in log_file encoding error in Windows fix dump file with Chinese charactor in Python 3 2.0.2 (2019-01-21) \u00b6 Fixed each teststeps in one testcase share the same session fix duplicate API definition output Changed display result from hook functions in DEBUG level log change log level of \"Variables & Output\" to INFO print Invalid testcase path or testcases print testcase output in INFO level log 2.0.1 (2019-01-18) \u00b6 Fixed override current teststep variables with former testcase output variables Fixed compatibility when testcase name is empty skip undefined variable when parsing string content Changed add back request method in report 2.0.0 (2019-01-01) \u00b6 Changed Massive Refactor and Simplification Redesign testcase structure Module pipline Start Semantic Versioning Switch to Apache 2.0 license Change logo","title":"CHANGELOG"},{"location":"CHANGELOG/#release-history","text":"","title":"Release History"},{"location":"CHANGELOG/#232-2019-11-01","text":"Changed make render_html_report separate with HttpRunner().run_tests() --report-file : specify report file path, this has higher priority than specifying report dir. remove summary property from HttpRunner","title":"2.3.2 (2019-11-01)"},{"location":"CHANGELOG/#231-2019-10-28","text":"Fixed fix locusts entry configuration Changed update PyPi classifiers","title":"2.3.1 (2019-10-28)"},{"location":"CHANGELOG/#230-2019-10-27","text":"Added feat: implement plugin system prototype, make locusts as plugin test: add Python 3.8 to Travis-CI feat: add __main__.py , python -m httprunner can be used to hrun tests Changed update dependency versions in pyproject.toml rename folder, httprunner/templates => httprunner/static log httprunner version before running tests remove unused import & code Fixed fix #707: duration stat error in multiple testsuites","title":"2.3.0 (2019-10-27)"},{"location":"CHANGELOG/#226-2019-09-18","text":"Added feat: config variables support parsing from function feat: support jsonpath to parse json response #679 feat: generate html report with specified report file #704 Changed remove unused import adjust code format Fixed fix: dev-rules link 404","title":"2.2.6 (2019-09-18)"},{"location":"CHANGELOG/#225-2019-07-28","text":"Added log HttpRunner version when initializing Fixed fix #658: sys.exit 1 if any testcase failed fix ModuleNotFoundError in debugging mode if httprunner uninstalled","title":"2.2.5 (2019-07-28)"},{"location":"CHANGELOG/#224-2019-07-18","text":"Changed replace pipenv & setup.py with poetry drop support for Python 3.4 as it was EOL on 2019-03-16 relocate debugging scripts, move from main-debug.py to httprunner.cli Fixed fix #574: delete unnecessary code fix #551: raise if times is not digit fix #572: tests_def_mapping[\"testcases\"] typo error","title":"2.2.4 (2019-07-18)"},{"location":"CHANGELOG/#223-2019-06-30","text":"Fixed fix yaml FullLoader AttributeError when PyYAML version < 5.1","title":"2.2.3 (2019-06-30)"},{"location":"CHANGELOG/#222-2019-06-26","text":"Changed extract is used to replace output when passing former teststep's (as a testcase) export value to next teststep export is used to replace output in testcase config","title":"2.2.2 (2019-06-26)"},{"location":"CHANGELOG/#221-2019-06-25","text":"Added add demo api/testcase/testsuite to new created scaffold project update default .gitignore of new created scaffold project add demo content to debugtalk.py / .env of new created scaffold project Fixed fix extend with testcase reference in format version 2 fix ImportError when locustio is not installed fix YAMLLoadWarning by specify yaml loader","title":"2.2.1 (2019-06-25)"},{"location":"CHANGELOG/#220-2019-06-24","text":"Added support testcase/testsuite in format version 2 Fixed add wheel in dev packages fix exception when teststep name reference former extracted variable","title":"2.2.0 (2019-06-24)"},{"location":"CHANGELOG/#213-2019-04-24","text":"Fixed replace eval mechanism with builtins to prevent security vulnerabilities ImportError for builtins in Python2.7","title":"2.1.3 (2019-04-24)"},{"location":"CHANGELOG/#212-2019-04-17","text":"Added support new variable notation ${var} use \\$\\$ to escape \\$ notation add Python 3.7 for travis CI Fixed match duplicate variable/function in single raw string escape '{' and '}' notation in raw string print_info: TypeError when value is None display api name when running api as testcase","title":"2.1.2 (2019-04-17)"},{"location":"CHANGELOG/#211-2019-04-11","text":"Changed refactor upload files mechanism with requests-toolbelt : simplify usage syntax, detect mimetype with filetype . support upload multiple fields.","title":"2.1.1 (2019-04-11)"},{"location":"CHANGELOG/#210-2019-04-10","text":"Added implement json dump Python objects when save tests implement lazy parser remove project_mapping from parse_tests result Fixed reference output variables pass output variables between testcases","title":"2.1.0 (2019-04-10)"},{"location":"CHANGELOG/#206-2019-03-18","text":"Added create .gitignore file when initializing new project Fixed fix CSV relative path detection fix current validators displaying the former one when they are empty","title":"2.0.6 (2019-03-18)"},{"location":"CHANGELOG/#205-2019-03-04","text":"Added implement method to get variables and output Fixed fix xss in response json","title":"2.0.5 (2019-03-04)"},{"location":"CHANGELOG/#204-2019-02-28","text":"Fixed fix verify priority with nested testcase fix function in config variables called multiple times dump loaded tests when running tests_mapping directly","title":"2.0.4 (2019-02-28)"},{"location":"CHANGELOG/#203-2019-02-24","text":"Fixed fix verify priority: teststep > config fix Chinese charactor in log_file encoding error in Windows fix dump file with Chinese charactor in Python 3","title":"2.0.3 (2019-02-24)"},{"location":"CHANGELOG/#202-2019-01-21","text":"Fixed each teststeps in one testcase share the same session fix duplicate API definition output Changed display result from hook functions in DEBUG level log change log level of \"Variables & Output\" to INFO print Invalid testcase path or testcases print testcase output in INFO level log","title":"2.0.2 (2019-01-21)"},{"location":"CHANGELOG/#201-2019-01-18","text":"Fixed override current teststep variables with former testcase output variables Fixed compatibility when testcase name is empty skip undefined variable when parsing string content Changed add back request method in report","title":"2.0.1 (2019-01-18)"},{"location":"CHANGELOG/#200-2019-01-01","text":"Changed Massive Refactor and Simplification Redesign testcase structure Module pipline Start Semantic Versioning Switch to Apache 2.0 license Change logo","title":"2.0.0 (2019-01-01)"},{"location":"FAQ/","text":"\u5e38\u89c1\u95ee\u9898 \u00b6","title":"FAQ"},{"location":"FAQ/#_1","text":"","title":"\u5e38\u89c1\u95ee\u9898"},{"location":"Installation/","text":"\u8fd0\u884c\u73af\u5883 \u00b6 HttpRunner \u662f\u4e00\u4e2a\u57fa\u4e8e Python \u5f00\u53d1\u7684\u6d4b\u8bd5\u6846\u67b6\uff0c\u53ef\u4ee5\u8fd0\u884c\u5728 macOS\u3001Linux\u3001Windows \u7cfb\u7edf\u5e73\u53f0\u4e0a\u3002 Python \u7248\u672c \uff1aHttpRunner \u652f\u6301 Python 3.4 \u53ca\u4ee5\u4e0a\u7684\u6240\u6709\u7248\u672c\uff0c\u5e76\u4f7f\u7528 Travis-CI \u8fdb\u884c\u4e86 \u6301\u7eed\u96c6\u6210\u6d4b\u8bd5 \uff0c\u6d4b\u8bd5\u8986\u76d6\u7684\u7248\u672c\u5305\u62ec 2.7/3.4/3.5/3.6/3.7\u3002\u867d\u7136 HttpRunner \u6682\u65f6\u4fdd\u7559\u4e86\u5bf9 Python 2.7 \u7684\u517c\u5bb9\u652f\u6301\uff0c\u4f46\u5f3a\u70c8\u5efa\u8bae\u4f7f\u7528 Python 3.4 \u53ca\u4ee5\u4e0a\u7248\u672c\u3002 \u64cd\u4f5c\u7cfb\u7edf \uff1a\u63a8\u8350\u4f7f\u7528 macOS/Linux\u3002 \u5b89\u88c5\u65b9\u5f0f \u00b6 HttpRunner \u7684\u7a33\u5b9a\u7248\u672c\u6258\u7ba1\u5728 PyPI \u4e0a\uff0c\u53ef\u4ee5\u4f7f\u7528 pip \u8fdb\u884c\u5b89\u88c5\u3002 $ pip install httprunner \u5982\u679c\u4f60\u9700\u8981\u4f7f\u7528\u6700\u65b0\u7684\u5f00\u53d1\u7248\u672c\uff0c\u90a3\u4e48\u53ef\u4ee5\u91c7\u7528\u9879\u76ee\u7684 GitHub \u4ed3\u5e93\u5730\u5740\u8fdb\u884c\u5b89\u88c5\uff1a $ pip install git+https://github.com/HttpRunner/HttpRunner.git@master \u7248\u672c\u5347\u7ea7 \u00b6 \u5047\u5982\u4f60\u4e4b\u524d\u5df2\u7ecf\u5b89\u88c5\u8fc7\u4e86 HttpRunner\uff0c\u73b0\u5728\u9700\u8981\u5347\u7ea7\u5230\u6700\u65b0\u7248\u672c\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528 -U \u53c2\u6570\u3002\u8be5\u53c2\u6570\u5bf9\u4ee5\u4e0a\u4e09\u79cd\u5b89\u88c5\u65b9\u5f0f\u5747\u751f\u6548\u3002 $ pip install -U HttpRunner $ pip install -U git+https://github.com/HttpRunner/HttpRunner.git@master \u5b89\u88c5\u6821\u9a8c \u00b6 \u5728 HttpRunner \u5b89\u88c5\u6210\u529f\u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e\u5982\u4e0b 5 \u4e2a\u547d\u4ee4\uff1a httprunner : \u6838\u5fc3\u547d\u4ee4 ate : \u66fe\u7ecf\u7528\u8fc7\u7684\u547d\u4ee4\uff08\u5f53\u65f6\u6846\u67b6\u540d\u79f0\u4e3a ApiTestEngine\uff09\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c hrun : httprunner \u7684\u7f29\u5199\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c locusts : \u57fa\u4e8e Locust \u5b9e\u73b0 \u6027\u80fd\u6d4b\u8bd5 har2case : \u8f85\u52a9\u5de5\u5177\uff0c\u53ef\u5c06\u6807\u51c6\u901a\u7528\u7684 HAR \u683c\u5f0f\uff08HTTP Archive\uff09\u8f6c\u6362\u4e3a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b httprunner\u3001hrun\u3001ate \u4e09\u4e2a\u547d\u4ee4\u5b8c\u5168\u7b49\u4ef7\uff0c\u529f\u80fd\u7279\u6027\u5b8c\u5168\u76f8\u540c\uff0c\u4e2a\u4eba\u63a8\u8350\u4f7f\u7528 hrun \u547d\u4ee4\u3002 \u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u82e5\u6b63\u5e38\u663e\u793a\u7248\u672c\u53f7\uff0c\u5219\u8bf4\u660e HttpRunner \u5b89\u88c5\u6210\u529f\u3002 $ hrun -V 2.0.2 $ har2case -V 0.2.0 \u5f00\u53d1\u8005\u6a21\u5f0f \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b89\u88c5 HttpRunner \u7684\u65f6\u5019\u53ea\u4f1a\u5b89\u88c5\u8fd0\u884c HttpRunner \u7684\u5fc5\u8981\u4f9d\u8d56\u5e93\u3002 \u5982\u679c\u4f60\u4e0d\u4ec5\u4ec5\u662f\u4f7f\u7528 HttpRunner\uff0c\u8fd8\u9700\u8981\u5bf9 HttpRunner \u8fdb\u884c\u5f00\u53d1\u8c03\u8bd5\uff08debug\uff09\uff0c\u90a3\u4e48\u5c31\u9700\u8981\u8fdb\u884c\u5982\u4e0b\u64cd\u4f5c\u3002 HttpRunner \u4f7f\u7528 pipenv \u5bf9\u4f9d\u8d56\u5305\u8fdb\u884c\u7ba1\u7406\uff0c\u82e5\u4f60\u8fd8\u6ca1\u6709\u5b89\u88c5 pipenv\uff0c\u9700\u8981\u5148\u6267\u884c\u5982\u4e0b\u547d\u4ee4\u8fdb\u884c\u6309\u7167\uff1a $ pip install pipenv \u83b7\u53d6 HttpRunner \u6e90\u7801\uff1a $ git clone https://github.com/HttpRunner/HttpRunner.git \u8fdb\u5165\u4ed3\u5e93\u76ee\u5f55\uff0c\u5b89\u88c5\u6240\u6709\u4f9d\u8d56\uff1a $ pipenv install --dev \u8fd0\u884c\u5355\u5143\u6d4b\u8bd5\uff0c\u82e5\u6d4b\u8bd5\u5168\u90e8\u901a\u8fc7\uff0c\u5219\u8bf4\u660e\u73af\u5883\u6b63\u5e38\u3002 $ pipenv run python -m unittest discover \u67e5\u770b HttpRunner \u7684\u4f9d\u8d56\u60c5\u51b5\uff1a $ pipenv graph HttpRunner==2.0.0 - colorama [required: Any, installed: 0.4.0] - colorlog [required: Any, installed: 3.1.4] - har2case [required: Any, installed: 0.2.0] - PyYAML [required: Any, installed: 3.13] - Jinja2 [required: Any, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - PyYAML [required: Any, installed: 3.13] - requests [required: Any, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] - requests-toolbelt [required: Any, installed: 0.8.0] - requests [required: >=2.0.1,<3.0.0, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] \u8c03\u8bd5\u8fd0\u884c\u65b9\u5f0f\uff1a # \u8c03\u8bd5\u8fd0\u884c hrun $ pipenv run python main-debug.py hrun -h # \u8c03\u8bd5\u8fd0\u884c locusts $ pipenv run python main-debug.py locusts -h Docker \u00b6 TODO","title":"\u5b89\u88c5\u8bf4\u660e"},{"location":"Installation/#_1","text":"HttpRunner \u662f\u4e00\u4e2a\u57fa\u4e8e Python \u5f00\u53d1\u7684\u6d4b\u8bd5\u6846\u67b6\uff0c\u53ef\u4ee5\u8fd0\u884c\u5728 macOS\u3001Linux\u3001Windows \u7cfb\u7edf\u5e73\u53f0\u4e0a\u3002 Python \u7248\u672c \uff1aHttpRunner \u652f\u6301 Python 3.4 \u53ca\u4ee5\u4e0a\u7684\u6240\u6709\u7248\u672c\uff0c\u5e76\u4f7f\u7528 Travis-CI \u8fdb\u884c\u4e86 \u6301\u7eed\u96c6\u6210\u6d4b\u8bd5 \uff0c\u6d4b\u8bd5\u8986\u76d6\u7684\u7248\u672c\u5305\u62ec 2.7/3.4/3.5/3.6/3.7\u3002\u867d\u7136 HttpRunner \u6682\u65f6\u4fdd\u7559\u4e86\u5bf9 Python 2.7 \u7684\u517c\u5bb9\u652f\u6301\uff0c\u4f46\u5f3a\u70c8\u5efa\u8bae\u4f7f\u7528 Python 3.4 \u53ca\u4ee5\u4e0a\u7248\u672c\u3002 \u64cd\u4f5c\u7cfb\u7edf \uff1a\u63a8\u8350\u4f7f\u7528 macOS/Linux\u3002","title":"\u8fd0\u884c\u73af\u5883"},{"location":"Installation/#_2","text":"HttpRunner \u7684\u7a33\u5b9a\u7248\u672c\u6258\u7ba1\u5728 PyPI \u4e0a\uff0c\u53ef\u4ee5\u4f7f\u7528 pip \u8fdb\u884c\u5b89\u88c5\u3002 $ pip install httprunner \u5982\u679c\u4f60\u9700\u8981\u4f7f\u7528\u6700\u65b0\u7684\u5f00\u53d1\u7248\u672c\uff0c\u90a3\u4e48\u53ef\u4ee5\u91c7\u7528\u9879\u76ee\u7684 GitHub \u4ed3\u5e93\u5730\u5740\u8fdb\u884c\u5b89\u88c5\uff1a $ pip install git+https://github.com/HttpRunner/HttpRunner.git@master","title":"\u5b89\u88c5\u65b9\u5f0f"},{"location":"Installation/#_3","text":"\u5047\u5982\u4f60\u4e4b\u524d\u5df2\u7ecf\u5b89\u88c5\u8fc7\u4e86 HttpRunner\uff0c\u73b0\u5728\u9700\u8981\u5347\u7ea7\u5230\u6700\u65b0\u7248\u672c\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528 -U \u53c2\u6570\u3002\u8be5\u53c2\u6570\u5bf9\u4ee5\u4e0a\u4e09\u79cd\u5b89\u88c5\u65b9\u5f0f\u5747\u751f\u6548\u3002 $ pip install -U HttpRunner $ pip install -U git+https://github.com/HttpRunner/HttpRunner.git@master","title":"\u7248\u672c\u5347\u7ea7"},{"location":"Installation/#_4","text":"\u5728 HttpRunner \u5b89\u88c5\u6210\u529f\u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e\u5982\u4e0b 5 \u4e2a\u547d\u4ee4\uff1a httprunner : \u6838\u5fc3\u547d\u4ee4 ate : \u66fe\u7ecf\u7528\u8fc7\u7684\u547d\u4ee4\uff08\u5f53\u65f6\u6846\u67b6\u540d\u79f0\u4e3a ApiTestEngine\uff09\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c hrun : httprunner \u7684\u7f29\u5199\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c locusts : \u57fa\u4e8e Locust \u5b9e\u73b0 \u6027\u80fd\u6d4b\u8bd5 har2case : \u8f85\u52a9\u5de5\u5177\uff0c\u53ef\u5c06\u6807\u51c6\u901a\u7528\u7684 HAR \u683c\u5f0f\uff08HTTP Archive\uff09\u8f6c\u6362\u4e3a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b httprunner\u3001hrun\u3001ate \u4e09\u4e2a\u547d\u4ee4\u5b8c\u5168\u7b49\u4ef7\uff0c\u529f\u80fd\u7279\u6027\u5b8c\u5168\u76f8\u540c\uff0c\u4e2a\u4eba\u63a8\u8350\u4f7f\u7528 hrun \u547d\u4ee4\u3002 \u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u82e5\u6b63\u5e38\u663e\u793a\u7248\u672c\u53f7\uff0c\u5219\u8bf4\u660e HttpRunner \u5b89\u88c5\u6210\u529f\u3002 $ hrun -V 2.0.2 $ har2case -V 0.2.0","title":"\u5b89\u88c5\u6821\u9a8c"},{"location":"Installation/#_5","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b89\u88c5 HttpRunner \u7684\u65f6\u5019\u53ea\u4f1a\u5b89\u88c5\u8fd0\u884c HttpRunner \u7684\u5fc5\u8981\u4f9d\u8d56\u5e93\u3002 \u5982\u679c\u4f60\u4e0d\u4ec5\u4ec5\u662f\u4f7f\u7528 HttpRunner\uff0c\u8fd8\u9700\u8981\u5bf9 HttpRunner \u8fdb\u884c\u5f00\u53d1\u8c03\u8bd5\uff08debug\uff09\uff0c\u90a3\u4e48\u5c31\u9700\u8981\u8fdb\u884c\u5982\u4e0b\u64cd\u4f5c\u3002 HttpRunner \u4f7f\u7528 pipenv \u5bf9\u4f9d\u8d56\u5305\u8fdb\u884c\u7ba1\u7406\uff0c\u82e5\u4f60\u8fd8\u6ca1\u6709\u5b89\u88c5 pipenv\uff0c\u9700\u8981\u5148\u6267\u884c\u5982\u4e0b\u547d\u4ee4\u8fdb\u884c\u6309\u7167\uff1a $ pip install pipenv \u83b7\u53d6 HttpRunner \u6e90\u7801\uff1a $ git clone https://github.com/HttpRunner/HttpRunner.git \u8fdb\u5165\u4ed3\u5e93\u76ee\u5f55\uff0c\u5b89\u88c5\u6240\u6709\u4f9d\u8d56\uff1a $ pipenv install --dev \u8fd0\u884c\u5355\u5143\u6d4b\u8bd5\uff0c\u82e5\u6d4b\u8bd5\u5168\u90e8\u901a\u8fc7\uff0c\u5219\u8bf4\u660e\u73af\u5883\u6b63\u5e38\u3002 $ pipenv run python -m unittest discover \u67e5\u770b HttpRunner \u7684\u4f9d\u8d56\u60c5\u51b5\uff1a $ pipenv graph HttpRunner==2.0.0 - colorama [required: Any, installed: 0.4.0] - colorlog [required: Any, installed: 3.1.4] - har2case [required: Any, installed: 0.2.0] - PyYAML [required: Any, installed: 3.13] - Jinja2 [required: Any, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - PyYAML [required: Any, installed: 3.13] - requests [required: Any, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] - requests-toolbelt [required: Any, installed: 0.8.0] - requests [required: >=2.0.1,<3.0.0, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] \u8c03\u8bd5\u8fd0\u884c\u65b9\u5f0f\uff1a # \u8c03\u8bd5\u8fd0\u884c hrun $ pipenv run python main-debug.py hrun -h # \u8c03\u8bd5\u8fd0\u884c locusts $ pipenv run python main-debug.py locusts -h","title":"\u5f00\u53d1\u8005\u6a21\u5f0f"},{"location":"Installation/#docker","text":"TODO","title":"Docker"},{"location":"quickstart/","text":"\u672c\u6587\u5c06\u901a\u8fc7\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\u6765\u5c55\u793a HttpRunner \u7684\u6838\u5fc3\u529f\u80fd\u4f7f\u7528\u65b9\u6cd5\u3002 \u6848\u4f8b\u4ecb\u7ecd \u00b6 \u8be5\u6848\u4f8b\u4f5c\u4e3a\u88ab\u6d4b\u670d\u52a1\uff0c\u4e3b\u8981\u6709\u4e24\u7c7b\u63a5\u53e3\uff1a \u6743\u9650\u6821\u9a8c\uff0c\u83b7\u53d6 token \u652f\u6301 CRUD \u64cd\u4f5c\u7684 RESTful APIs\uff0c\u6240\u6709\u63a5\u53e3\u7684\u8bf7\u6c42\u5934\u57df\u4e2d\u90fd\u5fc5\u987b\u5305\u542b\u6709\u6548\u7684 token \u6848\u4f8b\u7684\u5b9e\u73b0\u5f62\u5f0f\u4e3a flask \u5e94\u7528\u670d\u52a1\uff08 api_server.py \uff09\uff0c\u542f\u52a8\u65b9\u5f0f\u5982\u4e0b\uff1a $ export FLASK_APP=docs/data/api_server.py $ export FLASK_ENV=development $ flask run * Serving Flask app \"docs/data/api_server.py\" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 989-476-348 \u670d\u52a1\u542f\u52a8\u6210\u529f\u540e\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u5bf9\u5176\u8fdb\u884c\u6d4b\u8bd5\u4e86\u3002 \u6d4b\u8bd5\u51c6\u5907 \u00b6 \u6293\u5305\u5206\u6790 \u00b6 \u5728\u5f00\u59cb\u6d4b\u8bd5\u4e4b\u524d\uff0c\u6211\u4eec\u9700\u8981\u5148\u4e86\u89e3\u63a5\u53e3\u7684\u8bf7\u6c42\u548c\u54cd\u5e94\u7ec6\u8282\uff0c\u800c\u6700\u4f73\u7684\u65b9\u5f0f\u5c31\u662f\u91c7\u7528 Charles Proxy \u6216\u8005 Fiddler \u8fd9\u7c7b\u7f51\u7edc\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u5206\u6790\u3002 \u4f8b\u5982\uff0c\u5728\u672c\u6848\u4f8b\u4e2d\uff0c\u6211\u4eec\u5148\u8fdb\u884c\u6743\u9650\u6821\u9a8c\uff0c\u7136\u540e\u6210\u529f\u521b\u5efa\u4e00\u4e2a\u7528\u6237\uff0c\u5bf9\u5e94\u7684\u7f51\u7edc\u6293\u5305\u5185\u5bb9\u5982\u4e0b\u56fe\u6240\u793a\uff1a \u901a\u8fc7\u6293\u5305\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5177\u4f53\u7684\u63a5\u53e3\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684URL\u3001Method\u3001headers\u3001\u53c2\u6570\u548c\u54cd\u5e94\u5185\u5bb9\u7b49\u5185\u5bb9\uff0c\u57fa\u4e8e\u8fd9\u4e9b\u4fe1\u606f\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u7f16\u5199\u6d4b\u8bd5\u7528\u4f8b\u4e86\u3002 \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u4e3a\u4e86\u7b80\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7f16\u5199\u5de5\u4f5c\uff0cHttpRunner \u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u7684\u529f\u80fd\u3002 \u9996\u5148\uff0c\u9700\u8981\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\uff0c\u5047\u8bbe\u5bfc\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo-quickstart.har \u3002 \u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo-quickstart.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\uff0c\u52a0\u4e0a -2y \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002\u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002\u5173\u4e8e har2case \u7684\u8be6\u7ec6\u4f7f\u7528\u8bf4\u660e\uff0c\u8bf7\u67e5\u770b \u300a\u5f55\u5236\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u300b \u3002 \u7ecf\u8fc7\u8f6c\u6362\uff0c\u5728\u6e90 demo-quickstart.har \u6587\u4ef6\u7684\u540c\u7ea7\u76ee\u5f55\u4e0b\u751f\u6210\u4e86\u76f8\u540c\u6587\u4ef6\u540d\u79f0\u7684 YAML \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6 demo-quickstart.yml \uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a - config : name : testcase description variables : {} - test : name : /api/get-token request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : 2.8.6 device_sn : FwgRiO7CNA50DSU os_platform : ios json : sign : 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98 method : POST url : http://127.0.0.1:5000/api/get-token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.token , baNLX1zhFYP11Seb ] - test : name : /api/users/1000 request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 device_sn : FwgRiO7CNA50DSU token : baNLX1zhFYP11Seb json : name : user1 password : '123456' method : POST url : http://127.0.0.1:5000/api/users/1000 validate : - eq : [ status_code , 201 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.msg , user created successfully. ] \u73b0\u5728\u6211\u4eec\u53ea\u9700\u8981\u77e5\u9053\u5982\u4e0b\u51e0\u70b9\uff1a \u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e3a\u4e00\u4e2a list of dict \u7ed3\u6784\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 config \u4e3a\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b test \u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4f5c\u7528\u57df\u4ec5\u9650\u4e8e\u672c\u8eab \u5982\u4e0a\u4fbf\u662f HttpRunner \u6d4b\u8bd5\u7528\u4f8b\u7684\u57fa\u672c\u7ed3\u6784\u3002 \u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u63cf\u8ff0\u300b \u3002 \u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u6d4b\u8bd5\u7528\u4f8b\u5c31\u7eea\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f00\u59cb\u8c03\u8bd5\u8fd0\u884c\u4e86\u3002 \u4e3a\u4e86\u6f14\u793a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8fed\u4ee3\u4f18\u5316\u8fc7\u7a0b\uff0c\u6211\u4eec\u5148\u5c06 demo-quickstart.json \u91cd\u547d\u540d\u4e3a demo-quickstart-0.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-0.yml \uff09\u3002 \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u547d\u4ee4\u4e3a hrun \uff0c\u540e\u9762\u76f4\u63a5\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\u5373\u53ef\u3002 $ hrun docs/data/demo-quickstart-0.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.26 ms, response_length: 46 bytes ERROR validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/get-token method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios'} json: {'sign': '9c0c7e51c91ae963c833a4ccbab8d683c4a90c98'} verify: True ====== response details ====== status_code: 200 headers: {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": true, \"token\": \"tXGuSQgOCVXcltkz\"}' F /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0000_000 (httprunner.api.TestSequense) /api/get-token ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.026s FAILED (failures=2) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513835.html \u975e\u5e38\u4e0d\u5e78\uff0c\u4e24\u4e2a\u63a5\u53e3\u7684\u6d4b\u8bd5\u7528\u4f8b\u5747\u8fd0\u884c\u5931\u8d25\u4e86\u3002 \u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u4ece\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u62a5\u9519\u4fe1\u606f\u548c\u5806\u6808\u4fe1\u606f\uff08Traceback\uff09\u53ef\u4ee5\u770b\u51fa\uff0c\u7b2c\u4e00\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u83b7\u53d6\u7684 token \u4e0e\u9884\u671f\u503c\u4e0d\u4e00\u81f4\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u8bf7\u6c42\u6743\u9650\u6821\u9a8c\u5931\u8d25\uff08403\uff09\u3002 \u63a5\u4e0b\u6765\u6211\u4eec\u5c06\u9010\u6b65\u8fdb\u884c\u8fdb\u884c\u4f18\u5316\u3002 \u8c03\u6574\u6821\u9a8c\u5668 \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c har2case \u751f\u6210\u7528\u4f8b\u65f6\uff0c\u82e5 HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u4f1a\u5c06\u7b2c\u4e00\u5c42\u7ea7\u4e2d\u7684\u6240\u6709 key-value \u8f6c\u6362\u4e3a validator\u3002 \u4f8b\u5982\u4e0a\u9762\u7684\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u751f\u6210\u7684 validator \u4e3a\uff1a \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]} ] \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u5c31\u4f1a\u5bf9\u4e0a\u9762\u7684\u5404\u4e2a\u9879\u8fdb\u884c\u6821\u9a8c\u3002 \u95ee\u9898\u5728\u4e8e\uff0c\u8bf7\u6c42 /api/get-token \u63a5\u53e3\u65f6\uff0c\u6bcf\u6b21\u751f\u6210\u7684 token \u90fd\u4f1a\u662f\u4e0d\u540c\u7684\uff0c\u56e0\u6b64\u5c06\u751f\u6210\u7684 token \u4f5c\u4e3a\u6821\u9a8c\u9879\u7684\u8bdd\uff0c\u6821\u9a8c\u81ea\u7136\u5c31\u65e0\u6cd5\u901a\u8fc7\u4e86\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u5e94\u8be5\u53bb\u6389\u8fd9\u7c7b\u52a8\u6001\u53d8\u5316\u7684\u503c\u3002 \u53bb\u9664\u8be5\u9879\u540e\uff0c\u5c06\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-1.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-1.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-1.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 6.61 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:45:34 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.018s FAILED (failures=1) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513934.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5df2\u7ecf\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u5931\u8d25\uff08403\uff09\uff0c\u8fd8\u662f\u56e0\u4e3a\u6743\u9650\u6821\u9a8c\u7684\u539f\u56e0\u3002 \u53c2\u6570\u5173\u8054 \u00b6 \u6211\u4eec\u7ee7\u7eed\u67e5\u770b demo-quickstart-1.json \uff0c\u4f1a\u53d1\u73b0\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42 headers \u4e2d\u7684 token \u4ecd\u7136\u662f\u786c\u7f16\u7801\u7684\uff0c\u5373\u6293\u5305\u65f6\u83b7\u53d6\u5230\u7684\u503c\u3002\u5728\u6211\u4eec\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u8fd9\u4e2a token \u5df2\u7ecf\u5931\u6548\u4e86\uff0c\u6240\u4ee5\u4f1a\u51fa\u73b0 403 \u6743\u9650\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u6211\u4eec\u5e94\u8be5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u5148\u52a8\u6001\u83b7\u53d6\u5230\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 token\uff0c\u7136\u540e\u5728\u540e\u7eed\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42\u4e2d\u4f7f\u7528\u524d\u9762\u83b7\u53d6\u5230\u7684 token\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53c2\u6570\u63d0\u53d6\uff08 extract \uff09\u548c\u53c2\u6570\u5f15\u7528\u7684\u529f\u80fd\uff08 $var \uff09\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\uff0c\u82e5\u9700\u8981\u4ece\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5219\u53ef\u4f7f\u7528 extract \u5173\u952e\u5b57\u3002extract \u7684\u5217\u8868\u4e2d\u53ef\u6307\u5b9a\u4e00\u4e2a\u6216\u591a\u4e2a\u9700\u8981\u63d0\u53d6\u7684\u53c2\u6570\u3002 \u5728\u63d0\u53d6\u53c2\u6570\u65f6\uff0c\u5f53 HTTP \u7684\u8bf7\u6c42\u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u53ef\u4ee5\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u9010\u7ea7\u5f80\u4e0b\u83b7\u53d6\u5230\u53c2\u6570\u503c\uff1b\u54cd\u5e94\u7ed3\u679c\u7684\u6574\u4f53\u5185\u5bb9\u5f15\u7528\u65b9\u5f0f\u4e3a content \u6216\u8005 body\u3002 \u4f8b\u5982\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3 /api/get-token \u7684\u54cd\u5e94\u7ed3\u679c\u4e3a\uff1a { \"success\" : true , \"token\" : \"ZQkYhbaQ6q8UFFNE\" } \u90a3\u4e48\u8981\u83b7\u53d6\u5230 token \u53c2\u6570\uff0c\u5c31\u53ef\u4ee5\u4f7f\u7528 content.token \u7684\u65b9\u5f0f\uff1b\u5177\u4f53\u7684\u5199\u6cd5\u5982\u4e0b\uff1a \"extract\" : [ { \"token\" : \"content.token\" } ] \u5176\u4e2d\uff0ctoken \u4f5c\u4e3a\u63d0\u53d6\u540e\u7684\u53c2\u6570\u540d\u79f0\uff0c\u53ef\u4ee5\u5728\u540e\u7eed\u4f7f\u7528 $token \u8fdb\u884c\u5f15\u7528\u3002 \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" , \"Content-Type\" : \"application/json\" } \u4fee\u6539\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-2.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-2.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-2.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.32 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548514191.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e5f\u8fd0\u884c\u6210\u529f\u4e86\u3002 base_url \u00b6 \u867d\u7136\u6d4b\u8bd5\u6b65\u9aa4\u8fd0\u884c\u90fd\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4ecd\u7136\u6709\u7ee7\u7eed\u4f18\u5316\u7684\u5730\u65b9\u3002 \u7ee7\u7eed\u67e5\u770b demo-quickstart-2.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684 URL \u4e2d\uff0c\u90fd\u91c7\u7528\u7684\u662f\u5b8c\u6574\u7684\u63cf\u8ff0\uff08host+path\uff09\uff0c\u4f46\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u540c\u4e00\u4e2a\u7528\u4f8b\u4e2d\u7684 host \u90fd\u662f\u76f8\u540c\u7684\uff0c\u533a\u522b\u4ec5\u5728\u4e8e path \u90e8\u5206\u3002 \u56e0\u6b64\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 URL \u7684 base_url \u62bd\u53d6\u51fa\u6765\uff0c\u653e\u5230\u5168\u5c40\u914d\u7f6e\u6a21\u5757\uff08config\uff09\u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 URL \u53ea\u4fdd\u7559 PATH \u90e8\u5206\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 - test : name : get token request : url : /api/get-token \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-3.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-3.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002 \u53d8\u91cf\u7684\u7533\u660e\u548c\u5f15\u7528 \u00b6 \u7ee7\u7eed\u67e5\u770b demo-quickstart-3.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b58\u5728\u8f83\u591a\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u4f8b\u5982 app_version\u3001device_sn\u3001os_platform\u3001user_id \u7b49\u3002 \u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u53ef\u4ee5\u4e0d\u7528\u4fee\u6539\u8fd9\u4e9b\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u8fd0\u884c\u3002\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ef4\u62a4\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u540c\u4e00\u4e2a\u53c2\u6570\u503c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u51fa\u73b0\u591a\u6b21\uff0c\u90a3\u4e48\u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5c06\u8fd9\u4e9b\u53c2\u6570\u5b9a\u4e49\u4e3a\u53d8\u91cf\uff0c\u7136\u540e\u5728\u9700\u8981\u53c2\u6570\u7684\u5730\u65b9\u8fdb\u884c\u5f15\u7528\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53d8\u91cf\u7533\u660e\uff08 variables \uff09\u548c\u5f15\u7528\uff08 $var \uff09\u7684\u673a\u5236\u3002\u5728 config \u548c test \u4e2d\u5747\u53ef\u4ee5\u901a\u8fc7 variables \u5173\u952e\u5b57\u5b9a\u4e49\u53d8\u91cf\uff0c\u7136\u540e\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u53ef\u4ee5\u901a\u8fc7 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\u5f15\u7528\u53d8\u91cf\u3002\u533a\u522b\u5728\u4e8e\uff0c\u5728 config \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4e3a\u5168\u5c40\u7684\uff0c\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6240\u6709\u5730\u65b9\u5747\u53ef\u4ee5\u5f15\u7528\uff1b\u5728 test \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4f5c\u7528\u57df\u4ec5\u5c40\u9650\u4e8e\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u3002 \u5bf9\u4e0a\u8ff0\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u786c\u7f16\u7801\u7684\u53c2\u6570\u8fdb\u884c\u53d8\u91cf\u7533\u660e\u548c\u5f15\u7528\u8c03\u6574\u540e\uff0c\u65b0\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-4.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-4.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002 \u62bd\u53d6\u516c\u5171\u53d8\u91cf \u00b6 \u67e5\u770b demo-quickstart-4.json \u53ef\u4ee5\u770b\u51fa\uff0c\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u90fd\u5b9a\u4e49\u4e86 device_sn\u3002\u9488\u5bf9\u8fd9\u7c7b\u516c\u5171\u7684\u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5176\u7edf\u4e00\u5b9a\u4e49\u5728 config \u7684 variables \u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5c31\u4e0d\u7528\u518d\u91cd\u590d\u5b9a\u4e49\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 variables : device_sn : FwgRiO7CNA50DSU \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u89c1 demo-quickstart-5.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-5.yml \uff09\u3002 \u5b9e\u73b0\u52a8\u6001\u8fd0\u7b97\u903b\u8f91 \u00b6 \u5728 demo-quickstart-5.yml \u4e2d\uff0c\u53c2\u6570 device_sn \u4ee3\u8868\u7684\u662f\u8bbe\u5907\u7684 SN \u7f16\u7801\uff0c\u867d\u7136\u91c7\u7528\u786c\u7f16\u7801\u7684\u65b9\u5f0f\u6682\u65f6\u4e0d\u5f71\u54cd\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\uff0c\u4f46\u8fd9\u4e0e\u771f\u5b9e\u7684\u7528\u6237\u573a\u666f\u4e0d\u5927\u76f8\u7b26\u3002 \u5047\u8bbe device_sn \u7684\u683c\u5f0f\u4e3a 15 \u957f\u5ea6\u7684\u5b57\u7b26\u4e32\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u9488\u5bf9 device_sn \u751f\u6210\u4e00\u4e2a 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u3002\b\u4e0e\u6b64\u540c\u65f6\uff0csign \u5b57\u6bb5\u662f\u6839\u636e headers \u4e2d\u7684\u5404\u4e2a\u5b57\u6bb5\u62fc\u63a5\u540e\u751f\u6210\u5f97\u5230\u7684 MD5 \u503c\uff0c\u56e0\u6b64\u5728 device_sn \u53d8\u52a8\u540e\uff0csign \u4e5f\u5e94\u8be5\u91cd\u65b0\u8fdb\u884c\u8ba1\u7b97\uff0c\u5426\u5219\u5c31\u4f1a\u518d\u6b21\u51fa\u73b0\u7b7e\u540d\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u7136\u800c\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u91c7\u7528 YAML/JSON \u683c\u5f0f\u8fdb\u884c\u63cf\u8ff0\u7684\uff0c\u5728\u6587\u672c\u683c\u5f0f\u4e2d\u5982\u4f55\u6267\u884c\u4ee3\u7801\u8fd0\u7b97\u5462\uff1f HttpRunner \u7684\u5b9e\u73b0\u65b9\u5f0f\u4e3a\uff0c\u652f\u6301\u70ed\u52a0\u8f7d\u7684\u63d2\u4ef6\u673a\u5236\uff08 debugtalk.py \uff09\uff0c\u53ef\u4ee5\u5728 YAML/JSON \u4e2d\u8c03\u7528 Python \u51fd\u6570\u3002 \u5177\u4f53\u5730\u505a\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u540c\u7ea7\u6216\u5176\u7236\u7ea7\u76ee\u5f55\u4e2d\u521b\u5efa\u4e00\u4e2a debugtalk.py \u6587\u4ef6\uff0c\u7136\u540e\u5728\u5176\u4e2d\u5b9a\u4e49\u76f8\u5173\u7684\u51fd\u6570\u548c\u53d8\u91cf\u3002 \u4f8b\u5982\uff0c\u9488\u5bf9 device_sn \u7684\u968f\u673a\u5b57\u7b26\u4e32\u751f\u6210\u529f\u80fd\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a gen_random_string \u51fd\u6570\uff1b\u9488\u5bf9 sign \u7684\u7b7e\u540d\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a get_sign \u51fd\u6570\u3002 import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" def gen_random_string ( str_len ): random_char_list = [] for _ in range ( str_len ): random_char = random . choice ( string . ascii_letters + string . digits ) random_char_list . append ( random_char ) random_string = '' . join ( random_char_list ) return random_string def get_sign ( * args ): content = '' . join ( args ) . encode ( 'ascii' ) sign_key = SECRET_KEY . encode ( 'ascii' ) sign = hmac . new ( sign_key , content , hashlib . sha1 ) . hexdigest () return sign \u7136\u540e\uff0c\u6211\u4eec\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u5bf9\u5b9a\u4e49\u7684\u51fd\u6570\u8fdb\u884c\u8c03\u7528\uff0c\u5bf9\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4e86\u3002\u5f15\u7528\u53d8\u91cf\u7684\u65b9\u5f0f\u4ecd\u7136\u4e0e\u524d\u9762\u8bb2\u7684\u4e00\u6837\uff0c\u91c7\u7528 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\uff1b\u8c03\u7528\u51fd\u6570\u7684\u65b9\u5f0f\u4e3a ${func($var)} \u3002 \u4f8b\u5982\uff0c\u751f\u6210 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u5e76\u8d4b\u503c\u7ed9 device_sn \u7684\u4ee3\u7801\u4e3a\uff1a \"variables\" : [ { \"device_sn\" : \"${gen_random_string(15)}\" } ] \u4f7f\u7528 $user_agent\u3001$device_sn\u3001$os_platform\u3001$app_version \u6839\u636e\u7b7e\u540d\u7b97\u6cd5\u751f\u6210 sign \u503c\u7684\u4ee3\u7801\u4e3a\uff1a \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } \u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u4e0a\u8ff0\u8c03\u6574\u540e\uff0c\u53e6\u5b58\u4e3a demo-quickstart-6.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-6.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002 \u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8 \u00b6 \u8bf7\u786e\u4fdd\u4f60\u4f7f\u7528\u7684 HttpRunner \u7248\u672c\u53f7\u4e0d\u4f4e\u4e8e 2.0.0 \u5728 demo-quickstart-6.yml \u4e2d\uff0cuser_id \u4ecd\u7136\u662f\u5199\u6b7b\u7684\u503c\uff0c\u5047\u5982\u6211\u4eec\u9700\u8981\u521b\u5efa user_id \u4e3a 1001\uff5e1004 \u7684\u7528\u6237\uff0c\u90a3\u6211\u4eec\u53ea\u80fd\u4e0d\u65ad\u5730\u53bb\u4fee\u6539 user_id\uff0c\u7136\u540e\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u91cd\u590d\u64cd\u4f5c 4 \u6b21\uff1f\u6216\u8005\u6211\u4eec\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u5c06\u521b\u5efa\u7528\u6237\u7684 test \u590d\u5236 4 \u4efd\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u4efd\u91cc\u9762\u5206\u522b\u4f7f\u7528\u4e0d\u540c\u7684 user_id \uff1f \u5f88\u663e\u7136\uff0c\u4e0d\u7ba1\u662f\u91c7\u7528\u4e0a\u8ff0\u54ea\u79cd\u65b9\u5f0f\uff0c\u90fd\u4f1a\u5f88\u7e41\u7410\uff0c\u5e76\u4e14\u4e5f\u65e0\u6cd5\u5e94\u5bf9\u7075\u6d3b\u591a\u53d8\u7684\u6d4b\u8bd5\u9700\u6c42\u3002 \u9488\u5bf9\u8fd9\u7c7b\u9700\u6c42\uff0cHttpRunner \u652f\u6301\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u7684\u529f\u80fd\u3002 \u5728 HttpRunner \u4e2d\uff0c\u82e5\u8981\u91c7\u7528\u6570\u636e\u9a71\u52a8\u7684\u65b9\u5f0f\u6765\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\uff0c\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u5f15\u7528\uff0c\u5e76\u4f7f\u7528 parameters \u5173\u952e\u5b57\u5b9a\u4e49\u53c2\u6570\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u521b\u5efa\u7528\u6237\u7684\u63a5\u53e3\u4e2d\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\uff0c\u53c2\u6570\u5316\u5217\u8868\u4e3a 1001\uff5e1004\uff0c\u5e76\u4e14\u53d6\u503c\u65b9\u5f0f\u4e3a\u987a\u5e8f\u53d6\u503c\uff0c\u90a3\u4e48\u6700\u7b80\u5355\u7684\u63cf\u8ff0\u65b9\u5f0f\u5c31\u662f\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u3002\u5177\u4f53\u7684\u7f16\u5199\u65b9\u5f0f\u4e3a\uff0c\u65b0\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u573a\u666f\u6587\u4ef6 demo-quickstart-7.yml \uff08\u5bf9\u5e94\u7684 JSON \u683c\u5f0f\uff1a demo-quickstart-7.json \uff09\uff0c\u5185\u5bb9\u5982\u4e0b\u6240\u793a\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u4ec5\u9700\u5982\u4e0a\u914d\u7f6e\uff0c\u9488\u5bf9 user_id \u7684\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u5c31\u5b8c\u6210\u4e86\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u60c5\u51b5\u5982\u4e0b\u6240\u793a\uff1a \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002 \u5173\u4e8e\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u8fd9\u91cc\u53ea\u63cf\u8ff0\u4e86\u6700\u7b80\u5355\u7684\u573a\u666f\u548c\u4f7f\u7528\u65b9\u5f0f\uff0c\u5982\u9700\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u8fdb\u4e00\u6b65\u9605\u8bfb \u300a\u6570\u636e\u9a71\u52a8\u4f7f\u7528\u624b\u518c\u300b \u3002 \u67e5\u770b\u6d4b\u8bd5\u62a5\u544a \u00b6 \u5728\u6bcf\u6b21\u4f7f\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u5747\u4f1a\u751f\u6210\u4e00\u4efd HTML \u683c\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\u3002\u62a5\u544a\u6587\u4ef6\u4f4d\u4e8e reports \u76ee\u5f55\u4e0b\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5f00\u59cb\u8fd0\u884c\u65f6\u95f4\u3002 \u4f8b\u5982\uff0c\u5728\u8fd0\u884c\u5b8c demo-quickstart-1.json \u540e\uff0c\u5c06\u751f\u6210\u5982\u4e0b\u5f62\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\uff1a \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u62a5\u544a\u300b \u90e8\u5206\u3002 \u603b\u7ed3 \u00b6 \u5230\u6b64\u4e3a\u6b62\uff0cHttpRunner \u7684\u6838\u5fc3\u529f\u80fd\u5c31\u4ecb\u7ecd\u5b8c\u4e86\uff0c\u638c\u63e1\u672c\u6587\u4e2d\u7684\u529f\u80fd\u7279\u6027\uff0c\u8db3\u4ee5\u5e2e\u52a9\u4f60\u5e94\u5bf9\u65e5\u5e38\u9879\u76ee\u5de5\u4f5c\u4e2d\u81f3\u5c11 80% \u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\u3002 \u5f53\u7136\uff0cHttpRunner \u4e0d\u6b62\u4e8e\u6b64\uff0c\u5982\u9700\u6316\u6398 HttpRunner \u7684\u66f4\u591a\u7279\u6027\uff0c\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\uff0c\u53ef\u7ee7\u7eed\u9605\u8bfb\u540e\u7eed\u6587\u6863\u3002","title":"\u5feb\u901f\u4e0a\u624b"},{"location":"quickstart/#_1","text":"\u8be5\u6848\u4f8b\u4f5c\u4e3a\u88ab\u6d4b\u670d\u52a1\uff0c\u4e3b\u8981\u6709\u4e24\u7c7b\u63a5\u53e3\uff1a \u6743\u9650\u6821\u9a8c\uff0c\u83b7\u53d6 token \u652f\u6301 CRUD \u64cd\u4f5c\u7684 RESTful APIs\uff0c\u6240\u6709\u63a5\u53e3\u7684\u8bf7\u6c42\u5934\u57df\u4e2d\u90fd\u5fc5\u987b\u5305\u542b\u6709\u6548\u7684 token \u6848\u4f8b\u7684\u5b9e\u73b0\u5f62\u5f0f\u4e3a flask \u5e94\u7528\u670d\u52a1\uff08 api_server.py \uff09\uff0c\u542f\u52a8\u65b9\u5f0f\u5982\u4e0b\uff1a $ export FLASK_APP=docs/data/api_server.py $ export FLASK_ENV=development $ flask run * Serving Flask app \"docs/data/api_server.py\" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 989-476-348 \u670d\u52a1\u542f\u52a8\u6210\u529f\u540e\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u5bf9\u5176\u8fdb\u884c\u6d4b\u8bd5\u4e86\u3002","title":"\u6848\u4f8b\u4ecb\u7ecd"},{"location":"quickstart/#_2","text":"","title":"\u6d4b\u8bd5\u51c6\u5907"},{"location":"quickstart/#_3","text":"\u5728\u5f00\u59cb\u6d4b\u8bd5\u4e4b\u524d\uff0c\u6211\u4eec\u9700\u8981\u5148\u4e86\u89e3\u63a5\u53e3\u7684\u8bf7\u6c42\u548c\u54cd\u5e94\u7ec6\u8282\uff0c\u800c\u6700\u4f73\u7684\u65b9\u5f0f\u5c31\u662f\u91c7\u7528 Charles Proxy \u6216\u8005 Fiddler \u8fd9\u7c7b\u7f51\u7edc\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u5206\u6790\u3002 \u4f8b\u5982\uff0c\u5728\u672c\u6848\u4f8b\u4e2d\uff0c\u6211\u4eec\u5148\u8fdb\u884c\u6743\u9650\u6821\u9a8c\uff0c\u7136\u540e\u6210\u529f\u521b\u5efa\u4e00\u4e2a\u7528\u6237\uff0c\u5bf9\u5e94\u7684\u7f51\u7edc\u6293\u5305\u5185\u5bb9\u5982\u4e0b\u56fe\u6240\u793a\uff1a \u901a\u8fc7\u6293\u5305\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5177\u4f53\u7684\u63a5\u53e3\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684URL\u3001Method\u3001headers\u3001\u53c2\u6570\u548c\u54cd\u5e94\u5185\u5bb9\u7b49\u5185\u5bb9\uff0c\u57fa\u4e8e\u8fd9\u4e9b\u4fe1\u606f\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u7f16\u5199\u6d4b\u8bd5\u7528\u4f8b\u4e86\u3002","title":"\u6293\u5305\u5206\u6790"},{"location":"quickstart/#_4","text":"\u4e3a\u4e86\u7b80\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7f16\u5199\u5de5\u4f5c\uff0cHttpRunner \u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u7684\u529f\u80fd\u3002 \u9996\u5148\uff0c\u9700\u8981\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\uff0c\u5047\u8bbe\u5bfc\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo-quickstart.har \u3002 \u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo-quickstart.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\uff0c\u52a0\u4e0a -2y \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002\u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002\u5173\u4e8e har2case \u7684\u8be6\u7ec6\u4f7f\u7528\u8bf4\u660e\uff0c\u8bf7\u67e5\u770b \u300a\u5f55\u5236\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u300b \u3002 \u7ecf\u8fc7\u8f6c\u6362\uff0c\u5728\u6e90 demo-quickstart.har \u6587\u4ef6\u7684\u540c\u7ea7\u76ee\u5f55\u4e0b\u751f\u6210\u4e86\u76f8\u540c\u6587\u4ef6\u540d\u79f0\u7684 YAML \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6 demo-quickstart.yml \uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a - config : name : testcase description variables : {} - test : name : /api/get-token request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : 2.8.6 device_sn : FwgRiO7CNA50DSU os_platform : ios json : sign : 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98 method : POST url : http://127.0.0.1:5000/api/get-token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.token , baNLX1zhFYP11Seb ] - test : name : /api/users/1000 request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 device_sn : FwgRiO7CNA50DSU token : baNLX1zhFYP11Seb json : name : user1 password : '123456' method : POST url : http://127.0.0.1:5000/api/users/1000 validate : - eq : [ status_code , 201 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.msg , user created successfully. ] \u73b0\u5728\u6211\u4eec\u53ea\u9700\u8981\u77e5\u9053\u5982\u4e0b\u51e0\u70b9\uff1a \u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e3a\u4e00\u4e2a list of dict \u7ed3\u6784\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 config \u4e3a\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b test \u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4f5c\u7528\u57df\u4ec5\u9650\u4e8e\u672c\u8eab \u5982\u4e0a\u4fbf\u662f HttpRunner \u6d4b\u8bd5\u7528\u4f8b\u7684\u57fa\u672c\u7ed3\u6784\u3002 \u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u63cf\u8ff0\u300b \u3002","title":"\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b"},{"location":"quickstart/#_5","text":"\u6d4b\u8bd5\u7528\u4f8b\u5c31\u7eea\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f00\u59cb\u8c03\u8bd5\u8fd0\u884c\u4e86\u3002 \u4e3a\u4e86\u6f14\u793a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8fed\u4ee3\u4f18\u5316\u8fc7\u7a0b\uff0c\u6211\u4eec\u5148\u5c06 demo-quickstart.json \u91cd\u547d\u540d\u4e3a demo-quickstart-0.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-0.yml \uff09\u3002 \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u547d\u4ee4\u4e3a hrun \uff0c\u540e\u9762\u76f4\u63a5\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\u5373\u53ef\u3002 $ hrun docs/data/demo-quickstart-0.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.26 ms, response_length: 46 bytes ERROR validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/get-token method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios'} json: {'sign': '9c0c7e51c91ae963c833a4ccbab8d683c4a90c98'} verify: True ====== response details ====== status_code: 200 headers: {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": true, \"token\": \"tXGuSQgOCVXcltkz\"}' F /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0000_000 (httprunner.api.TestSequense) /api/get-token ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.026s FAILED (failures=2) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513835.html \u975e\u5e38\u4e0d\u5e78\uff0c\u4e24\u4e2a\u63a5\u53e3\u7684\u6d4b\u8bd5\u7528\u4f8b\u5747\u8fd0\u884c\u5931\u8d25\u4e86\u3002","title":"\u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b"},{"location":"quickstart/#_6","text":"\u4ece\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u62a5\u9519\u4fe1\u606f\u548c\u5806\u6808\u4fe1\u606f\uff08Traceback\uff09\u53ef\u4ee5\u770b\u51fa\uff0c\u7b2c\u4e00\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u83b7\u53d6\u7684 token \u4e0e\u9884\u671f\u503c\u4e0d\u4e00\u81f4\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u8bf7\u6c42\u6743\u9650\u6821\u9a8c\u5931\u8d25\uff08403\uff09\u3002 \u63a5\u4e0b\u6765\u6211\u4eec\u5c06\u9010\u6b65\u8fdb\u884c\u8fdb\u884c\u4f18\u5316\u3002","title":"\u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b"},{"location":"quickstart/#_7","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c har2case \u751f\u6210\u7528\u4f8b\u65f6\uff0c\u82e5 HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u4f1a\u5c06\u7b2c\u4e00\u5c42\u7ea7\u4e2d\u7684\u6240\u6709 key-value \u8f6c\u6362\u4e3a validator\u3002 \u4f8b\u5982\u4e0a\u9762\u7684\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u751f\u6210\u7684 validator \u4e3a\uff1a \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]} ] \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u5c31\u4f1a\u5bf9\u4e0a\u9762\u7684\u5404\u4e2a\u9879\u8fdb\u884c\u6821\u9a8c\u3002 \u95ee\u9898\u5728\u4e8e\uff0c\u8bf7\u6c42 /api/get-token \u63a5\u53e3\u65f6\uff0c\u6bcf\u6b21\u751f\u6210\u7684 token \u90fd\u4f1a\u662f\u4e0d\u540c\u7684\uff0c\u56e0\u6b64\u5c06\u751f\u6210\u7684 token \u4f5c\u4e3a\u6821\u9a8c\u9879\u7684\u8bdd\uff0c\u6821\u9a8c\u81ea\u7136\u5c31\u65e0\u6cd5\u901a\u8fc7\u4e86\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u5e94\u8be5\u53bb\u6389\u8fd9\u7c7b\u52a8\u6001\u53d8\u5316\u7684\u503c\u3002 \u53bb\u9664\u8be5\u9879\u540e\uff0c\u5c06\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-1.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-1.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-1.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 6.61 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:45:34 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.018s FAILED (failures=1) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513934.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5df2\u7ecf\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u5931\u8d25\uff08403\uff09\uff0c\u8fd8\u662f\u56e0\u4e3a\u6743\u9650\u6821\u9a8c\u7684\u539f\u56e0\u3002","title":"\u8c03\u6574\u6821\u9a8c\u5668"},{"location":"quickstart/#_8","text":"\u6211\u4eec\u7ee7\u7eed\u67e5\u770b demo-quickstart-1.json \uff0c\u4f1a\u53d1\u73b0\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42 headers \u4e2d\u7684 token \u4ecd\u7136\u662f\u786c\u7f16\u7801\u7684\uff0c\u5373\u6293\u5305\u65f6\u83b7\u53d6\u5230\u7684\u503c\u3002\u5728\u6211\u4eec\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u8fd9\u4e2a token \u5df2\u7ecf\u5931\u6548\u4e86\uff0c\u6240\u4ee5\u4f1a\u51fa\u73b0 403 \u6743\u9650\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u6211\u4eec\u5e94\u8be5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u5148\u52a8\u6001\u83b7\u53d6\u5230\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 token\uff0c\u7136\u540e\u5728\u540e\u7eed\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42\u4e2d\u4f7f\u7528\u524d\u9762\u83b7\u53d6\u5230\u7684 token\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53c2\u6570\u63d0\u53d6\uff08 extract \uff09\u548c\u53c2\u6570\u5f15\u7528\u7684\u529f\u80fd\uff08 $var \uff09\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\uff0c\u82e5\u9700\u8981\u4ece\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5219\u53ef\u4f7f\u7528 extract \u5173\u952e\u5b57\u3002extract \u7684\u5217\u8868\u4e2d\u53ef\u6307\u5b9a\u4e00\u4e2a\u6216\u591a\u4e2a\u9700\u8981\u63d0\u53d6\u7684\u53c2\u6570\u3002 \u5728\u63d0\u53d6\u53c2\u6570\u65f6\uff0c\u5f53 HTTP \u7684\u8bf7\u6c42\u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u53ef\u4ee5\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u9010\u7ea7\u5f80\u4e0b\u83b7\u53d6\u5230\u53c2\u6570\u503c\uff1b\u54cd\u5e94\u7ed3\u679c\u7684\u6574\u4f53\u5185\u5bb9\u5f15\u7528\u65b9\u5f0f\u4e3a content \u6216\u8005 body\u3002 \u4f8b\u5982\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3 /api/get-token \u7684\u54cd\u5e94\u7ed3\u679c\u4e3a\uff1a { \"success\" : true , \"token\" : \"ZQkYhbaQ6q8UFFNE\" } \u90a3\u4e48\u8981\u83b7\u53d6\u5230 token \u53c2\u6570\uff0c\u5c31\u53ef\u4ee5\u4f7f\u7528 content.token \u7684\u65b9\u5f0f\uff1b\u5177\u4f53\u7684\u5199\u6cd5\u5982\u4e0b\uff1a \"extract\" : [ { \"token\" : \"content.token\" } ] \u5176\u4e2d\uff0ctoken \u4f5c\u4e3a\u63d0\u53d6\u540e\u7684\u53c2\u6570\u540d\u79f0\uff0c\u53ef\u4ee5\u5728\u540e\u7eed\u4f7f\u7528 $token \u8fdb\u884c\u5f15\u7528\u3002 \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" , \"Content-Type\" : \"application/json\" } \u4fee\u6539\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-2.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-2.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-2.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.32 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548514191.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e5f\u8fd0\u884c\u6210\u529f\u4e86\u3002","title":"\u53c2\u6570\u5173\u8054"},{"location":"quickstart/#base_url","text":"\u867d\u7136\u6d4b\u8bd5\u6b65\u9aa4\u8fd0\u884c\u90fd\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4ecd\u7136\u6709\u7ee7\u7eed\u4f18\u5316\u7684\u5730\u65b9\u3002 \u7ee7\u7eed\u67e5\u770b demo-quickstart-2.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684 URL \u4e2d\uff0c\u90fd\u91c7\u7528\u7684\u662f\u5b8c\u6574\u7684\u63cf\u8ff0\uff08host+path\uff09\uff0c\u4f46\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u540c\u4e00\u4e2a\u7528\u4f8b\u4e2d\u7684 host \u90fd\u662f\u76f8\u540c\u7684\uff0c\u533a\u522b\u4ec5\u5728\u4e8e path \u90e8\u5206\u3002 \u56e0\u6b64\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 URL \u7684 base_url \u62bd\u53d6\u51fa\u6765\uff0c\u653e\u5230\u5168\u5c40\u914d\u7f6e\u6a21\u5757\uff08config\uff09\u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 URL \u53ea\u4fdd\u7559 PATH \u90e8\u5206\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 - test : name : get token request : url : /api/get-token \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-3.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-3.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002","title":"base_url"},{"location":"quickstart/#_9","text":"\u7ee7\u7eed\u67e5\u770b demo-quickstart-3.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b58\u5728\u8f83\u591a\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u4f8b\u5982 app_version\u3001device_sn\u3001os_platform\u3001user_id \u7b49\u3002 \u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u53ef\u4ee5\u4e0d\u7528\u4fee\u6539\u8fd9\u4e9b\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u8fd0\u884c\u3002\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ef4\u62a4\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u540c\u4e00\u4e2a\u53c2\u6570\u503c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u51fa\u73b0\u591a\u6b21\uff0c\u90a3\u4e48\u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5c06\u8fd9\u4e9b\u53c2\u6570\u5b9a\u4e49\u4e3a\u53d8\u91cf\uff0c\u7136\u540e\u5728\u9700\u8981\u53c2\u6570\u7684\u5730\u65b9\u8fdb\u884c\u5f15\u7528\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53d8\u91cf\u7533\u660e\uff08 variables \uff09\u548c\u5f15\u7528\uff08 $var \uff09\u7684\u673a\u5236\u3002\u5728 config \u548c test \u4e2d\u5747\u53ef\u4ee5\u901a\u8fc7 variables \u5173\u952e\u5b57\u5b9a\u4e49\u53d8\u91cf\uff0c\u7136\u540e\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u53ef\u4ee5\u901a\u8fc7 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\u5f15\u7528\u53d8\u91cf\u3002\u533a\u522b\u5728\u4e8e\uff0c\u5728 config \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4e3a\u5168\u5c40\u7684\uff0c\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6240\u6709\u5730\u65b9\u5747\u53ef\u4ee5\u5f15\u7528\uff1b\u5728 test \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4f5c\u7528\u57df\u4ec5\u5c40\u9650\u4e8e\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u3002 \u5bf9\u4e0a\u8ff0\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u786c\u7f16\u7801\u7684\u53c2\u6570\u8fdb\u884c\u53d8\u91cf\u7533\u660e\u548c\u5f15\u7528\u8c03\u6574\u540e\uff0c\u65b0\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-4.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-4.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002","title":"\u53d8\u91cf\u7684\u7533\u660e\u548c\u5f15\u7528"},{"location":"quickstart/#_10","text":"\u67e5\u770b demo-quickstart-4.json \u53ef\u4ee5\u770b\u51fa\uff0c\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u90fd\u5b9a\u4e49\u4e86 device_sn\u3002\u9488\u5bf9\u8fd9\u7c7b\u516c\u5171\u7684\u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5176\u7edf\u4e00\u5b9a\u4e49\u5728 config \u7684 variables \u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5c31\u4e0d\u7528\u518d\u91cd\u590d\u5b9a\u4e49\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 variables : device_sn : FwgRiO7CNA50DSU \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u89c1 demo-quickstart-5.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-5.yml \uff09\u3002","title":"\u62bd\u53d6\u516c\u5171\u53d8\u91cf"},{"location":"quickstart/#_11","text":"\u5728 demo-quickstart-5.yml \u4e2d\uff0c\u53c2\u6570 device_sn \u4ee3\u8868\u7684\u662f\u8bbe\u5907\u7684 SN \u7f16\u7801\uff0c\u867d\u7136\u91c7\u7528\u786c\u7f16\u7801\u7684\u65b9\u5f0f\u6682\u65f6\u4e0d\u5f71\u54cd\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\uff0c\u4f46\u8fd9\u4e0e\u771f\u5b9e\u7684\u7528\u6237\u573a\u666f\u4e0d\u5927\u76f8\u7b26\u3002 \u5047\u8bbe device_sn \u7684\u683c\u5f0f\u4e3a 15 \u957f\u5ea6\u7684\u5b57\u7b26\u4e32\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u9488\u5bf9 device_sn \u751f\u6210\u4e00\u4e2a 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u3002\b\u4e0e\u6b64\u540c\u65f6\uff0csign \u5b57\u6bb5\u662f\u6839\u636e headers \u4e2d\u7684\u5404\u4e2a\u5b57\u6bb5\u62fc\u63a5\u540e\u751f\u6210\u5f97\u5230\u7684 MD5 \u503c\uff0c\u56e0\u6b64\u5728 device_sn \u53d8\u52a8\u540e\uff0csign \u4e5f\u5e94\u8be5\u91cd\u65b0\u8fdb\u884c\u8ba1\u7b97\uff0c\u5426\u5219\u5c31\u4f1a\u518d\u6b21\u51fa\u73b0\u7b7e\u540d\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u7136\u800c\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u91c7\u7528 YAML/JSON \u683c\u5f0f\u8fdb\u884c\u63cf\u8ff0\u7684\uff0c\u5728\u6587\u672c\u683c\u5f0f\u4e2d\u5982\u4f55\u6267\u884c\u4ee3\u7801\u8fd0\u7b97\u5462\uff1f HttpRunner \u7684\u5b9e\u73b0\u65b9\u5f0f\u4e3a\uff0c\u652f\u6301\u70ed\u52a0\u8f7d\u7684\u63d2\u4ef6\u673a\u5236\uff08 debugtalk.py \uff09\uff0c\u53ef\u4ee5\u5728 YAML/JSON \u4e2d\u8c03\u7528 Python \u51fd\u6570\u3002 \u5177\u4f53\u5730\u505a\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u540c\u7ea7\u6216\u5176\u7236\u7ea7\u76ee\u5f55\u4e2d\u521b\u5efa\u4e00\u4e2a debugtalk.py \u6587\u4ef6\uff0c\u7136\u540e\u5728\u5176\u4e2d\u5b9a\u4e49\u76f8\u5173\u7684\u51fd\u6570\u548c\u53d8\u91cf\u3002 \u4f8b\u5982\uff0c\u9488\u5bf9 device_sn \u7684\u968f\u673a\u5b57\u7b26\u4e32\u751f\u6210\u529f\u80fd\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a gen_random_string \u51fd\u6570\uff1b\u9488\u5bf9 sign \u7684\u7b7e\u540d\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a get_sign \u51fd\u6570\u3002 import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" def gen_random_string ( str_len ): random_char_list = [] for _ in range ( str_len ): random_char = random . choice ( string . ascii_letters + string . digits ) random_char_list . append ( random_char ) random_string = '' . join ( random_char_list ) return random_string def get_sign ( * args ): content = '' . join ( args ) . encode ( 'ascii' ) sign_key = SECRET_KEY . encode ( 'ascii' ) sign = hmac . new ( sign_key , content , hashlib . sha1 ) . hexdigest () return sign \u7136\u540e\uff0c\u6211\u4eec\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u5bf9\u5b9a\u4e49\u7684\u51fd\u6570\u8fdb\u884c\u8c03\u7528\uff0c\u5bf9\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4e86\u3002\u5f15\u7528\u53d8\u91cf\u7684\u65b9\u5f0f\u4ecd\u7136\u4e0e\u524d\u9762\u8bb2\u7684\u4e00\u6837\uff0c\u91c7\u7528 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\uff1b\u8c03\u7528\u51fd\u6570\u7684\u65b9\u5f0f\u4e3a ${func($var)} \u3002 \u4f8b\u5982\uff0c\u751f\u6210 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u5e76\u8d4b\u503c\u7ed9 device_sn \u7684\u4ee3\u7801\u4e3a\uff1a \"variables\" : [ { \"device_sn\" : \"${gen_random_string(15)}\" } ] \u4f7f\u7528 $user_agent\u3001$device_sn\u3001$os_platform\u3001$app_version \u6839\u636e\u7b7e\u540d\u7b97\u6cd5\u751f\u6210 sign \u503c\u7684\u4ee3\u7801\u4e3a\uff1a \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } \u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u4e0a\u8ff0\u8c03\u6574\u540e\uff0c\u53e6\u5b58\u4e3a demo-quickstart-6.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-6.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002","title":"\u5b9e\u73b0\u52a8\u6001\u8fd0\u7b97\u903b\u8f91"},{"location":"quickstart/#_12","text":"\u8bf7\u786e\u4fdd\u4f60\u4f7f\u7528\u7684 HttpRunner \u7248\u672c\u53f7\u4e0d\u4f4e\u4e8e 2.0.0 \u5728 demo-quickstart-6.yml \u4e2d\uff0cuser_id \u4ecd\u7136\u662f\u5199\u6b7b\u7684\u503c\uff0c\u5047\u5982\u6211\u4eec\u9700\u8981\u521b\u5efa user_id \u4e3a 1001\uff5e1004 \u7684\u7528\u6237\uff0c\u90a3\u6211\u4eec\u53ea\u80fd\u4e0d\u65ad\u5730\u53bb\u4fee\u6539 user_id\uff0c\u7136\u540e\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u91cd\u590d\u64cd\u4f5c 4 \u6b21\uff1f\u6216\u8005\u6211\u4eec\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u5c06\u521b\u5efa\u7528\u6237\u7684 test \u590d\u5236 4 \u4efd\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u4efd\u91cc\u9762\u5206\u522b\u4f7f\u7528\u4e0d\u540c\u7684 user_id \uff1f \u5f88\u663e\u7136\uff0c\u4e0d\u7ba1\u662f\u91c7\u7528\u4e0a\u8ff0\u54ea\u79cd\u65b9\u5f0f\uff0c\u90fd\u4f1a\u5f88\u7e41\u7410\uff0c\u5e76\u4e14\u4e5f\u65e0\u6cd5\u5e94\u5bf9\u7075\u6d3b\u591a\u53d8\u7684\u6d4b\u8bd5\u9700\u6c42\u3002 \u9488\u5bf9\u8fd9\u7c7b\u9700\u6c42\uff0cHttpRunner \u652f\u6301\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u7684\u529f\u80fd\u3002 \u5728 HttpRunner \u4e2d\uff0c\u82e5\u8981\u91c7\u7528\u6570\u636e\u9a71\u52a8\u7684\u65b9\u5f0f\u6765\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\uff0c\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u5f15\u7528\uff0c\u5e76\u4f7f\u7528 parameters \u5173\u952e\u5b57\u5b9a\u4e49\u53c2\u6570\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u521b\u5efa\u7528\u6237\u7684\u63a5\u53e3\u4e2d\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\uff0c\u53c2\u6570\u5316\u5217\u8868\u4e3a 1001\uff5e1004\uff0c\u5e76\u4e14\u53d6\u503c\u65b9\u5f0f\u4e3a\u987a\u5e8f\u53d6\u503c\uff0c\u90a3\u4e48\u6700\u7b80\u5355\u7684\u63cf\u8ff0\u65b9\u5f0f\u5c31\u662f\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u3002\u5177\u4f53\u7684\u7f16\u5199\u65b9\u5f0f\u4e3a\uff0c\u65b0\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u573a\u666f\u6587\u4ef6 demo-quickstart-7.yml \uff08\u5bf9\u5e94\u7684 JSON \u683c\u5f0f\uff1a demo-quickstart-7.json \uff09\uff0c\u5185\u5bb9\u5982\u4e0b\u6240\u793a\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u4ec5\u9700\u5982\u4e0a\u914d\u7f6e\uff0c\u9488\u5bf9 user_id \u7684\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u5c31\u5b8c\u6210\u4e86\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u60c5\u51b5\u5982\u4e0b\u6240\u793a\uff1a \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002 \u5173\u4e8e\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u8fd9\u91cc\u53ea\u63cf\u8ff0\u4e86\u6700\u7b80\u5355\u7684\u573a\u666f\u548c\u4f7f\u7528\u65b9\u5f0f\uff0c\u5982\u9700\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u8fdb\u4e00\u6b65\u9605\u8bfb \u300a\u6570\u636e\u9a71\u52a8\u4f7f\u7528\u624b\u518c\u300b \u3002","title":"\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8"},{"location":"quickstart/#_13","text":"\u5728\u6bcf\u6b21\u4f7f\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u5747\u4f1a\u751f\u6210\u4e00\u4efd HTML \u683c\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\u3002\u62a5\u544a\u6587\u4ef6\u4f4d\u4e8e reports \u76ee\u5f55\u4e0b\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5f00\u59cb\u8fd0\u884c\u65f6\u95f4\u3002 \u4f8b\u5982\uff0c\u5728\u8fd0\u884c\u5b8c demo-quickstart-1.json \u540e\uff0c\u5c06\u751f\u6210\u5982\u4e0b\u5f62\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\uff1a \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u62a5\u544a\u300b \u90e8\u5206\u3002","title":"\u67e5\u770b\u6d4b\u8bd5\u62a5\u544a"},{"location":"quickstart/#_14","text":"\u5230\u6b64\u4e3a\u6b62\uff0cHttpRunner \u7684\u6838\u5fc3\u529f\u80fd\u5c31\u4ecb\u7ecd\u5b8c\u4e86\uff0c\u638c\u63e1\u672c\u6587\u4e2d\u7684\u529f\u80fd\u7279\u6027\uff0c\u8db3\u4ee5\u5e2e\u52a9\u4f60\u5e94\u5bf9\u65e5\u5e38\u9879\u76ee\u5de5\u4f5c\u4e2d\u81f3\u5c11 80% \u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\u3002 \u5f53\u7136\uff0cHttpRunner \u4e0d\u6b62\u4e8e\u6b64\uff0c\u5982\u9700\u6316\u6398 HttpRunner \u7684\u66f4\u591a\u7279\u6027\uff0c\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\uff0c\u53ef\u7ee7\u7eed\u9605\u8bfb\u540e\u7eed\u6587\u6863\u3002","title":"\u603b\u7ed3"},{"location":"related-docs/","text":"\u5f00\u53d1\u7b14\u8bb0 \u00b6 DebugTalk \u6f14\u8bb2 \u00b6 MTSC 2018 : \u300a\u5927\u7586\u4e92\u8054\u7f51\u7684\u4e00\u7ad9\u5f0f\u81ea\u52a8\u5316\u6d4b\u8bd5\u89e3\u51b3\u65b9\u6848\uff08\u57fa\u4e8eHttpRunner\uff09\u300b PyCon China 2018 : \u300a\u501f\u52a9 Python \u5f00\u6e90\u751f\u6001\u6253\u9020\u4f01\u4e1a\u7ea7\u81ea\u52a8\u5316\u6d4b\u8bd5\u6846\u67b6\uff08HttpRunner\uff09\u300b MTSC 2019 : \u300aHttpRunner 2.0 \u6280\u672f\u67b6\u6784\u4e0e\u63a5\u53e3\u6d4b\u8bd5\u5e94\u7528\u300b","title":"\u76f8\u5173\u8d44\u6599"},{"location":"related-docs/#_1","text":"DebugTalk","title":"\u5f00\u53d1\u7b14\u8bb0"},{"location":"related-docs/#_2","text":"MTSC 2018 : \u300a\u5927\u7586\u4e92\u8054\u7f51\u7684\u4e00\u7ad9\u5f0f\u81ea\u52a8\u5316\u6d4b\u8bd5\u89e3\u51b3\u65b9\u6848\uff08\u57fa\u4e8eHttpRunner\uff09\u300b PyCon China 2018 : \u300a\u501f\u52a9 Python \u5f00\u6e90\u751f\u6001\u6253\u9020\u4f01\u4e1a\u7ea7\u81ea\u52a8\u5316\u6d4b\u8bd5\u6846\u67b6\uff08HttpRunner\uff09\u300b MTSC 2019 : \u300aHttpRunner 2.0 \u6280\u672f\u67b6\u6784\u4e0e\u63a5\u53e3\u6d4b\u8bd5\u5e94\u7528\u300b","title":"\u6f14\u8bb2"},{"location":"sponsors/","text":"\u8d5e\u52a9\u5546 \u00b6 \u611f\u8c22\u5404\u4f4d\u5bf9 HttpRunner \u7684\u8d5e\u52a9\u652f\u6301\uff01 \u91d1\u724c\u8d5e\u52a9\u5546\uff08Gold Sponsor\uff09 \u00b6 \u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662 \u662f\u7531\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u4e0e\u77e5\u540d\u8f6f\u4ef6\u6d4b\u8bd5\u793e\u533a TesterHome \u5408\u4f5c\u7684\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\u3002\u7531 BAT \u4e00\u7ebf \u6d4b\u8bd5\u5927\u5496\u6267\u6559 \uff0c\u63d0\u4f9b \u5b9e\u6218\u9a71\u52a8 \u7684\u63a5\u53e3\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u79fb\u52a8\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u6027\u80fd\u6d4b\u8bd5\u3001\u6301\u7eed\u96c6\u6210\u4e0e DevOps \u7b49\u6280\u672f\u57f9\u8bad\uff0c\u4ee5\u53ca\u6d4b\u8bd5\u5f00\u53d1\u4f18\u79c0\u4eba\u624d\u5185\u63a8\u670d\u52a1\u3002 \u70b9\u51fb\u5b66\u4e60! \u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662\u662f HttpRunner \u7684\u9996\u5bb6\u91d1\u724c\u8d5e\u52a9\u5546\u3002 \u6210\u4e3a\u8d5e\u52a9\u5546 \u00b6 \u5982\u679c\u4f60\u6240\u5728\u7684\u516c\u53f8\u6216\u4e2a\u4eba\u4e5f\u60f3\u5bf9 HttpRunner \u8fdb\u884c\u8d5e\u52a9\uff0c\u53ef\u53c2\u8003\u5982\u4e0b\u65b9\u6848\uff0c\u5177\u4f53\u53ef\u8054\u7cfb \u9879\u76ee\u4f5c\u8005 \u3002 \u7b49\u7ea7 \u91d1\u724c\u8d5e\u52a9\u5546 \uff08Gold Sponsor\uff09 \u94f6\u724c\u8d5e\u52a9\u5546 \uff08Silver Sponsor\uff09 \u4e2a\u4eba\u8d5e\u8d4f \u91d1\u989d \uffe510000/\u5e74 \uffe55000/\u5e74 \u4efb\u610f \u6743\u76ca \u516c\u53f8 logo\uff08\u5927\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 150 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u516c\u53f8 logo\uff08\u4e2d\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 50 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u4e2a\u4eba ID \u548c\u94fe\u63a5\u5c55\u793a\u5728 sponsors.md","title":"\u8d5e\u52a9\u5546"},{"location":"sponsors/#_1","text":"\u611f\u8c22\u5404\u4f4d\u5bf9 HttpRunner \u7684\u8d5e\u52a9\u652f\u6301\uff01","title":"\u8d5e\u52a9\u5546"},{"location":"sponsors/#gold-sponsor","text":"\u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662 \u662f\u7531\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u4e0e\u77e5\u540d\u8f6f\u4ef6\u6d4b\u8bd5\u793e\u533a TesterHome \u5408\u4f5c\u7684\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\u3002\u7531 BAT \u4e00\u7ebf \u6d4b\u8bd5\u5927\u5496\u6267\u6559 \uff0c\u63d0\u4f9b \u5b9e\u6218\u9a71\u52a8 \u7684\u63a5\u53e3\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u79fb\u52a8\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u6027\u80fd\u6d4b\u8bd5\u3001\u6301\u7eed\u96c6\u6210\u4e0e DevOps \u7b49\u6280\u672f\u57f9\u8bad\uff0c\u4ee5\u53ca\u6d4b\u8bd5\u5f00\u53d1\u4f18\u79c0\u4eba\u624d\u5185\u63a8\u670d\u52a1\u3002 \u70b9\u51fb\u5b66\u4e60! \u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662\u662f HttpRunner \u7684\u9996\u5bb6\u91d1\u724c\u8d5e\u52a9\u5546\u3002","title":"\u91d1\u724c\u8d5e\u52a9\u5546\uff08Gold Sponsor\uff09"},{"location":"sponsors/#_2","text":"\u5982\u679c\u4f60\u6240\u5728\u7684\u516c\u53f8\u6216\u4e2a\u4eba\u4e5f\u60f3\u5bf9 HttpRunner \u8fdb\u884c\u8d5e\u52a9\uff0c\u53ef\u53c2\u8003\u5982\u4e0b\u65b9\u6848\uff0c\u5177\u4f53\u53ef\u8054\u7cfb \u9879\u76ee\u4f5c\u8005 \u3002 \u7b49\u7ea7 \u91d1\u724c\u8d5e\u52a9\u5546 \uff08Gold Sponsor\uff09 \u94f6\u724c\u8d5e\u52a9\u5546 \uff08Silver Sponsor\uff09 \u4e2a\u4eba\u8d5e\u8d4f \u91d1\u989d \uffe510000/\u5e74 \uffe55000/\u5e74 \u4efb\u610f \u6743\u76ca \u516c\u53f8 logo\uff08\u5927\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 150 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u516c\u53f8 logo\uff08\u4e2d\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 50 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u4e2a\u4eba ID \u548c\u94fe\u63a5\u5c55\u793a\u5728 sponsors.md","title":"\u6210\u4e3a\u8d5e\u52a9\u5546"},{"location":"concept/nominal/","text":"\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u00b6 \u4ece 2.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u5f00\u59cb\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u7684\u5b9a\u4e49\u8fdb\u884c\u8fdb\u4e00\u6b65\u7684\u660e\u786e\uff0c\u53c2\u8003 wiki \u4e0a\u7684\u63cf\u8ff0\u3002 A test case is a specification of the inputs, execution conditions, testing procedure, and expected results that define a single test to be executed to achieve a particular software testing objective, such as to exercise a particular program path or to verify compliance with a specific requirement. \u6982\u62ec\u4e0b\u6765\uff0c\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u4e3a\u4e86\u6d4b\u8bd5\u67d0\u4e2a\u7279\u5b9a\u7684\u529f\u80fd\u903b\u8f91\u800c\u7cbe\u5fc3\u8bbe\u8ba1\u7684\uff0c\u5e76\u4e14\u81f3\u5c11\u5305\u542b\u5982\u4e0b\u51e0\u70b9\uff1a \u660e\u786e\u7684\u6d4b\u8bd5\u76ee\u7684\uff08achieve a particular software testing objective\uff09 \u660e\u786e\u7684\u8f93\u5165\uff08inputs\uff09 \u660e\u786e\u7684\u8fd0\u884c\u73af\u5883\uff08execution conditions\uff09 \u660e\u786e\u7684\u6d4b\u8bd5\u6b65\u9aa4\u63cf\u8ff0\uff08testing procedure\uff09 \u660e\u786e\u7684\u9884\u671f\u7ed3\u679c\uff08expected results\uff09 \u5bf9\u5e94\u5730\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u65b9\u5f0f\u8fdb\u884c\u5982\u4e0b\u8bbe\u8ba1\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684\uff1b\u5728 HttpRunner \u4e2d\uff0c\u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u3002 \u6d4b\u8bd5\u7528\u4f8b\u5305\u542b \u6d4b\u8bd5\u811a\u672c \u548c \u6d4b\u8bd5\u6570\u636e \u4e24\u90e8\u5206\uff1a \u6d4b\u8bd5\u7528\u4f8b = \u6d4b\u8bd5\u811a\u672c + \u6d4b\u8bd5\u6570\u636e \u6d4b\u8bd5\u811a\u672c \u91cd\u70b9\u662f\u63cf\u8ff0\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u529f\u80fd\u903b\u8f91 \uff0c\u5305\u62ec\u9884\u7f6e\u6761\u4ef6\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u9884\u671f\u7ed3\u679c\u7b49\uff0c\u5e76\u4e14\u53ef\u4ee5\u7ed3\u5408\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\u5b9e\u73b0\u590d\u6742\u7684\u8fd0\u7b97\u903b\u8f91\uff1b\u53ef\u4ee5\u5c06 \u6d4b\u8bd5\u811a\u672c \u7406\u89e3\u4e3a\u7f16\u7a0b\u8bed\u8a00\u4e2d\u7684 \u7c7b\uff08class\uff09 \uff1b \u6d4b\u8bd5\u6570\u636e \u91cd\u70b9\u662f\u5bf9\u5e94\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u6570\u636e\u903b\u8f91 \uff0c\u53ef\u4ee5\u7406\u89e3\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u6570\u636e\uff1b \u6d4b\u8bd5\u6570\u636e \u548c \u6d4b\u8bd5\u811a\u672c \u5206\u79bb\u540e\uff0c\u5c31\u53ef\u4ee5\u6bd4\u8f83\u65b9\u4fbf\u5730\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u6d4b\u8bd5\uff0c\u901a\u8fc7\u5bf9\u6d4b\u8bd5\u811a\u672c\u4f20\u5165\u4e00\u7ec4\u6570\u636e\uff0c\u5b9e\u73b0\u540c\u4e00\u4e1a\u52a1\u529f\u80fd\u5728\u4e0d\u540c\u6570\u636e\u903b\u8f91\u4e0b\u7684\u6d4b\u8bd5\u9a8c\u8bc1\u3002 \u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09 \u00b6 \u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u800c\u5bf9\u4e8e\u63a5\u53e3\u6d4b\u8bd5\u6765\u8bf4\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5e94\u8be5\u5c31\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0\u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09 \u00b6 \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\u3002 \u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u600e\u4e48\u529e\uff0c\u4f8b\u5982\u767b\u5f55\u529f\u80fd\u548c\u4e0b\u5355\u529f\u80fd\u3002\u6b63\u786e\u7684\u505a\u6cd5\u5e94\u8be5\u662f\uff0c\u5728\u4e0b\u5355\u6d4b\u8bd5\u7528\u4f8b\u7684\u524d\u7f6e\u6b65\u9aa4\u4e2d\u6267\u884c\u767b\u5f55\u64cd\u4f5c\u3002 - config : name : order product - test : name : login testcase : testcases/login.yml - test : name : add to cart api : api/add_cart.yml - test : name : make order api : api/make_order.yml \u6d4b\u8bd5\u573a\u666f \u00b6 \u6d4b\u8bd5\u573a\u666f \u548c \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f\u540c\u4e00\u6982\u5ff5\uff0c\u90fd\u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\u3002 \u63a5\u53e3 \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u53c2\u6570 \u53d8\u91cf \u6d4b\u8bd5\u811a\u672c\uff08YAML/JSON\uff09 debugtalk.py \u73af\u5883\u53d8\u91cf \u9879\u76ee\u6839\u76ee\u5f55 \u00b6","title":"\u540d\u8bcd\u89e3\u91ca"},{"location":"concept/nominal/#testcase","text":"\u4ece 2.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u5f00\u59cb\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u7684\u5b9a\u4e49\u8fdb\u884c\u8fdb\u4e00\u6b65\u7684\u660e\u786e\uff0c\u53c2\u8003 wiki \u4e0a\u7684\u63cf\u8ff0\u3002 A test case is a specification of the inputs, execution conditions, testing procedure, and expected results that define a single test to be executed to achieve a particular software testing objective, such as to exercise a particular program path or to verify compliance with a specific requirement. \u6982\u62ec\u4e0b\u6765\uff0c\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u4e3a\u4e86\u6d4b\u8bd5\u67d0\u4e2a\u7279\u5b9a\u7684\u529f\u80fd\u903b\u8f91\u800c\u7cbe\u5fc3\u8bbe\u8ba1\u7684\uff0c\u5e76\u4e14\u81f3\u5c11\u5305\u542b\u5982\u4e0b\u51e0\u70b9\uff1a \u660e\u786e\u7684\u6d4b\u8bd5\u76ee\u7684\uff08achieve a particular software testing objective\uff09 \u660e\u786e\u7684\u8f93\u5165\uff08inputs\uff09 \u660e\u786e\u7684\u8fd0\u884c\u73af\u5883\uff08execution conditions\uff09 \u660e\u786e\u7684\u6d4b\u8bd5\u6b65\u9aa4\u63cf\u8ff0\uff08testing procedure\uff09 \u660e\u786e\u7684\u9884\u671f\u7ed3\u679c\uff08expected results\uff09 \u5bf9\u5e94\u5730\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u65b9\u5f0f\u8fdb\u884c\u5982\u4e0b\u8bbe\u8ba1\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684\uff1b\u5728 HttpRunner \u4e2d\uff0c\u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u3002 \u6d4b\u8bd5\u7528\u4f8b\u5305\u542b \u6d4b\u8bd5\u811a\u672c \u548c \u6d4b\u8bd5\u6570\u636e \u4e24\u90e8\u5206\uff1a \u6d4b\u8bd5\u7528\u4f8b = \u6d4b\u8bd5\u811a\u672c + \u6d4b\u8bd5\u6570\u636e \u6d4b\u8bd5\u811a\u672c \u91cd\u70b9\u662f\u63cf\u8ff0\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u529f\u80fd\u903b\u8f91 \uff0c\u5305\u62ec\u9884\u7f6e\u6761\u4ef6\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u9884\u671f\u7ed3\u679c\u7b49\uff0c\u5e76\u4e14\u53ef\u4ee5\u7ed3\u5408\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\u5b9e\u73b0\u590d\u6742\u7684\u8fd0\u7b97\u903b\u8f91\uff1b\u53ef\u4ee5\u5c06 \u6d4b\u8bd5\u811a\u672c \u7406\u89e3\u4e3a\u7f16\u7a0b\u8bed\u8a00\u4e2d\u7684 \u7c7b\uff08class\uff09 \uff1b \u6d4b\u8bd5\u6570\u636e \u91cd\u70b9\u662f\u5bf9\u5e94\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u6570\u636e\u903b\u8f91 \uff0c\u53ef\u4ee5\u7406\u89e3\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u6570\u636e\uff1b \u6d4b\u8bd5\u6570\u636e \u548c \u6d4b\u8bd5\u811a\u672c \u5206\u79bb\u540e\uff0c\u5c31\u53ef\u4ee5\u6bd4\u8f83\u65b9\u4fbf\u5730\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u6d4b\u8bd5\uff0c\u901a\u8fc7\u5bf9\u6d4b\u8bd5\u811a\u672c\u4f20\u5165\u4e00\u7ec4\u6570\u636e\uff0c\u5b9e\u73b0\u540c\u4e00\u4e1a\u52a1\u529f\u80fd\u5728\u4e0d\u540c\u6570\u636e\u903b\u8f91\u4e0b\u7684\u6d4b\u8bd5\u9a8c\u8bc1\u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09"},{"location":"concept/nominal/#teststep","text":"\u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u800c\u5bf9\u4e8e\u63a5\u53e3\u6d4b\u8bd5\u6765\u8bf4\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5e94\u8be5\u5c31\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0\u3002","title":"\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09"},{"location":"concept/nominal/#testsuite","text":"\u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\u3002 \u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u600e\u4e48\u529e\uff0c\u4f8b\u5982\u767b\u5f55\u529f\u80fd\u548c\u4e0b\u5355\u529f\u80fd\u3002\u6b63\u786e\u7684\u505a\u6cd5\u5e94\u8be5\u662f\uff0c\u5728\u4e0b\u5355\u6d4b\u8bd5\u7528\u4f8b\u7684\u524d\u7f6e\u6b65\u9aa4\u4e2d\u6267\u884c\u767b\u5f55\u64cd\u4f5c\u3002 - config : name : order product - test : name : login testcase : testcases/login.yml - test : name : add to cart api : api/add_cart.yml - test : name : make order api : api/make_order.yml","title":"\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09"},{"location":"concept/nominal/#_1","text":"\u6d4b\u8bd5\u573a\u666f \u548c \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f\u540c\u4e00\u6982\u5ff5\uff0c\u90fd\u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\u3002 \u63a5\u53e3 \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u53c2\u6570 \u53d8\u91cf \u6d4b\u8bd5\u811a\u672c\uff08YAML/JSON\uff09 debugtalk.py \u73af\u5883\u53d8\u91cf","title":"\u6d4b\u8bd5\u573a\u666f"},{"location":"concept/nominal/#_2","text":"","title":"\u9879\u76ee\u6839\u76ee\u5f55"},{"location":"development/architecture/","text":"","title":"Pipline"},{"location":"development/dev-api/","text":"\u5f00\u53d1\u6269\u5c55 \u00b6 HttpRunner \u9664\u4e86\u4f5c\u4e3a\u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f5c\u4e3a\u8f6f\u4ef6\u5305\u96c6\u6210\u5230\u4f60\u81ea\u5df1\u7684\u9879\u76ee\u4e2d\u3002 \u7b80\u5355\u6765\u8bf4\uff0cHttpRunner \u63d0\u4f9b\u4e86\u8fd0\u884c YAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u7684\u80fd\u529b\uff0c\u5e76\u80fd\u8fd4\u56de\u8be6\u7ec6\u7684\u6d4b\u8bd5\u7ed3\u679c\u4fe1\u606f\u3002 HttpRunner class \u00b6 HttpRunner \u4ee5 \u7c7b\uff08class\uff09 \u7684\u5f62\u5f0f\u5bf9\u5916\u63d0\u4f9b\u8c03\u7528\u652f\u6301\uff0c\u7c7b\u540d\b\u4e3a HttpRunner \uff0c\u5bfc\u5165\u65b9\u5f0f\u5982\u4e0b\uff1a from httprunner.api import HttpRunner \u53ef\u7528\u521d\u59cb\u5316\u53c2\u6570 \u00b6 HttpRunner \u5185\u90e8\b\u7528\u4e8e\u9a71\u52a8\u6d4b\u8bd5\u6267\u884c\u7684\u662f unittest.TextTestRunner \uff0c\u5728\u521d\u59cb\u5316 HttpRunner \u65f6\u53ef\u4ee5\u4f7f\u7528 TextTestRunner \u7684\u6240\u6709\u53ef\u7528\u53c2\u6570\uff08\u8be6\u60c5\u53ef\u9605\u8bfb \u5b98\u65b9\u6587\u6863 \uff09\u3002\u9664\u6b64\u4e4b\u5916\uff0c HttpRunner \u8fd8\u989d\u5916\u652f\u6301\u4e00\u4e2a\u53c2\u6570\uff0c http_client_session \uff0c\u53ef\u7528\u4e8e\u6307\u5b9a\u4e0d\u540c\u7684\u5ba2\u6237\u7aef\u7c7b\u578b\u3002 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u521d\u59cb\u5316 HttpRunner \u65f6\u5e38\u7528\u7684\u53c2\u6570\u6709\u5982\u4e0b\u51e0\u4e2a\uff1a resultclass : HtmlTestResult/TextTestResult\uff0c\u9ed8\u8ba4\u503c\u4e3a HtmlTestResult failfast : \u8bbe\u7f6e\u4e3a True \u65f6\uff0c\u6d4b\u8bd5\u5728\u9996\u6b21\u9047\u5230\u9519\u8bef\u6216\u5931\u8d25\u65f6\u4f1a\u505c\u6b62\u8fd0\u884c\uff1b\u9ed8\u8ba4\u503c\u4e3a False http_client_session : \u4f20\u5165 requests.Session() \u65f6\u8fdb\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff08\u9ed8\u8ba4\uff09\uff0c\u4f20\u5165 locust.client.Session() \u65f6\u8fdb\u884c\u6027\u80fd\u6d4b\u8bd5 \u4f8b\u5982\uff0c\u5982\u9700\u521d\u59cb\u5316 HttpRunner \u65f6\u8bbe\u7f6e failfast \u4e3a False\uff0c\b\u521d\u59cb\u5316\u65b9\u5f0f\u5982\u4e0b\u6240\u793a\uff1a from httprunner.api import HttpRunner runner = HttpRunner ( failfast = False ) \b\u53ef\u7528\u8c03\u7528\u65b9\u6cd5 \u00b6 \u5728 HttpRunner \u4e2d\uff0c\u5bf9\u5916\u63d0\u4f9b\u4e86\u4e24\u4e2a\u65b9\u6cd5\uff1a run : \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b gen_html_report : \u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a \u53ef\u7528\u5c5e\u6027 \u00b6 \u5728 HttpRunner \u4e2d\uff0c\u5bf9\u5916\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5c5e\u6027\uff1a summary : \u6d4b\u8bd5\u6267\u884c\u7ed3\u679c \u8be5\u5c5e\u6027\u9700\u8981\u5728\u8c03\u7528 run \u65b9\u6cd5\u540e\u83b7\u53d6\u3002 \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b \u00b6 HttpRunner \u7684 run \u65b9\u6cd5\u6709\u4e09\u4e2a\u53c2\u6570\uff1a path_or_testcases : \u6307\u5b9a\u8981\u8fd0\u884c\u7684\u6d4b\u8bd5\u7528\u4f8b\uff1b\u652f\u6301\u4f20\u5165\u4e24\u7c7b\u53c2\u6570\uff0cYAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\uff0c\u6216\u8005\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\uff1b dot_env_path \uff08\u53ef\u9009\uff09: \u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u9ed8\u8ba4\u503c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e2d\u7684 .env \u6587\u4ef6 mapping \uff08\u53ef\u9009\uff09: \u53d8\u91cf\u6620\u5c04\uff0c\u53ef\u7528\u4e8e\u5bf9\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\u3002 \u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84 \u00b6 \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u652f\u6301\u4e09\u79cd\u5f62\u5f0f\uff1a YAML/JSON \u6587\u4ef6\u8def\u5f84\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u5305\u542b YAML/JSON \u6587\u4ef6\u7684\u6587\u4ef6\u5939\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u6587\u4ef6\u8def\u5f84\u548c\u6587\u4ef6\u5939\u8def\u5f84\u7684\u6df7\u5408\u60c5\u51b5\uff08list/set\uff09 # \u6587\u4ef6\u8def\u5f84 runner . run ( \"docs/data/demo-quickstart-2.yml\" ) # \u6587\u4ef6\u5939\u8def\u5f84 runner . run ( \"docs/data/\" ) # \u6df7\u5408\u60c5\u51b5 runner . run ([ \"docs/data/\" , \"files/demo-quickstart-2.yml\" ]) \u5982\u9700\u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u6216\u8005\u9700\u8981\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\uff0c\u5219\u53ef\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\u3002 # dot_env_path runner . run ( \"docs/data/demo-quickstart-2.yml\" , dot_env_path = \"/path/to/.env\" ) # mapping override_mapping = { \"device_sn\" : \"XXX\" } runner . run ( \"docs/data/demo-quickstart-2.yml\" , mapping = override_mapping ) \u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53 \u00b6 \u9664\u4e86\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\uff0c\u8fd8\u53ef\u4ee5\u76f4\u63a5\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u3002 \u4ee5 demo-quickstart-2.yml \u4e3a\u4f8b\uff0c\u5bf9\u5e94\u7684\u6570\u636e\u7ed3\u6784\u4f53\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { \"name\" : \"testcase description\" , \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" } }, \"variables\" : [], \"output\" : [ \"token\" ], \"path\" : \"/abs-path/to/demo-quickstart-2.yml\" , \"refs\" : { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" :, \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } }, \"teststeps\" : [ { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" }, \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ] }, { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" }, \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [ { \"eq\" : [ \"status_code\" , 201 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]} ] } ] }, { ... } # another testcase ] \u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u65f6\uff0c\u652f\u6301\u4f20\u5165\u5355\u4e2a\u7ed3\u6784\u4f53\uff08dict\uff09\uff0c\u6216\u8005\u591a\u4e2a\u7ed3\u6784\u4f53\uff08list of dict\uff09\u3002 # \u8fd0\u884c\u5355\u4e2a\u7ed3\u6784\u4f53 runner . run ( testcase ) # \u8fd0\u884c\u591a\u4e2a\u7ed3\u6784\u4f53 runner . run ([ testcase1 , testcase2 ]) \u52a0\u8f7d debugtalk.py && .env \u00b6 \b\u901a\u8fc7\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\bHttpRunner \u4f1a\u81ea\u52a8\u4ee5\b\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u4e3a\u8d77\u70b9\uff0c\u5411\u4e0a\u641c\u7d22 debugtalk.py \u6587\u4ef6\uff0c\u5e76\u5c06 debugtalk.py \u6587\u4ef6\u6240\u5728\u7684\u6587\u4ef6\u76ee\u5f55\u4f5c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u3002 \u540c\u65f6\uff0cHttpRunner \u4f1a\u5728\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e0b\b\b\u641c\u7d22 .env \u6587\u4ef6\uff0c\u4ee5\u53ca api \u548c testcases \u6587\u4ef6\u5939\uff0c\u5e76\u81ea\u52a8\u8fdb\u884c\u52a0\u8f7d\u3002 \u6700\u7ec8\u52a0\u8f7d\u5f97\u5230\u7684\u5b58\u50a8\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } \u5176\u4e2d\uff0c env \u5bf9\u5e94\u7684\u662f .env \u6587\u4ef6\u4e2d\u7684\u73af\u5883\u53d8\u91cf\uff0c debugtalk \u5bf9\u5e94\u7684\u662f debugtalk.py \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u548c\u51fd\u6570\uff0c def-api \u5bf9\u5e94\u7684\u662f api \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u63a5\u53e3\u63cf\u8ff0\uff0c def-testcase \u5bf9\u5e94\u7684\u662f testcases \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u6d4b\u8bd5\u7528\u4f8b\u3002 \u901a\u8fc7\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u6267\u884c\u6d4b\u8bd5\u65f6\uff0c\u4f20\u5165\u7684\u6570\u636e\u5e94\u5305\u542b\u6240\u6709\u4fe1\u606f\uff0c\u5305\u62ec debugtalk.py \u3001 .env \u3001\u4f9d\u8d56\u7684 api \u548c \u6d4b\u8bd5\u7528\u4f8b\u7b49\uff1b\u56e0\u6b64\u4e5f\u65e0\u9700\u518d\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\uff0c\u6240\u6709\u4fe1\u606f\u90fd\u8981\u901a\u8fc7 refs \u4f20\u5165\u3002 \u8fd4\u56de\u8be6\u7ec6\u6d4b\u8bd5\u7ed3\u679c\u6570\u636e \u00b6 \u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u901a\u8fc7 summary \u5c5e\u6027\u53ef\u83b7\u53d6\u8be6\u5c3d\u7684\u8fd0\u884c\u7ed3\u679c\u6570\u636e\u3002 # get result summary summary = runner . summary \u5176\u6570\u636e\u7ed3\u6784\u4e3a\uff1a { \"success\" : true , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"platform\" : { \"httprunner_version\" : \"1.5.14\" , \"python_version\" : \"CPython 3.6.5+\" , \"platform\" : \"Darwin-17.6.0-x86_64-i386-64bit\" }, \"details\" : [ { \"success\" : true , \"name\" : \"testcase description\" , \"base_url\" : \"\" , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"records\" : [ { \"name\" : \"/api/get-token\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" , \"Content-Length\" : \"52\" }, \"start_timestamp\" : 1538449655.944801 , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }, \"body\" : b' { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } ' }, \"response\" : { \"status_code\" : 200 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"46\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 46 , \"response_time_ms\" : 12.87 , \"elapsed_ms\" : 6.955 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"reason\" : \"OK\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"json\" : { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 200 , \"comparator\" : \"eq\" , \"check_value\" : 200 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" } ] } }, { \"name\" : \"/api/users/1000\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"CcQ7dBjZZbjIXRkG\" , \"Content-Length\" : \"39\" }, \"start_timestamp\" : 1538449655.958944 , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }, \"body\" : b' { \"name\" : \"user1\" , \"password\" : \"123456\" } ' }, \"response\" : { \"status_code\" : 201 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"54\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 54 , \"response_time_ms\" : 3.34 , \"elapsed_ms\" : 2.16 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"reason\" : \"CREATED\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"json\" : { \"success\" : true , \"msg\" : \"user created successfully.\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 201 , \"comparator\" : \"eq\" , \"check_value\" : 201 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" }, { \"check\" : \"content.msg\" , \"expect\" : \"user created successfully.\" , \"comparator\" : \"eq\" , \"check_value\" : \"user created successfully.\" , \"check_result\" : \"pass\" } ] } } ], \"in_out\" : { \"in\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"out\" : { \"token\" : \"CcQ7dBjZZbjIXRkG\" } } } ] } \u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a \u00b6 \u5982\u9700\u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u53ef\u8c03\u7528 gen_html_report \u65b9\u6cd5\u3002 # generate html report runner . gen_html_report ( html_report_name = \"demo\" , html_report_template = \"/path/to/custom_report_template\" ) # => reports/demo/demo-1532078874.html \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u90e8\u5206\u3002","title":"\u57fa\u7840\u5e93\u8c03\u7528"},{"location":"development/dev-api/#_1","text":"HttpRunner \u9664\u4e86\u4f5c\u4e3a\u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f5c\u4e3a\u8f6f\u4ef6\u5305\u96c6\u6210\u5230\u4f60\u81ea\u5df1\u7684\u9879\u76ee\u4e2d\u3002 \u7b80\u5355\u6765\u8bf4\uff0cHttpRunner \u63d0\u4f9b\u4e86\u8fd0\u884c YAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u7684\u80fd\u529b\uff0c\u5e76\u80fd\u8fd4\u56de\u8be6\u7ec6\u7684\u6d4b\u8bd5\u7ed3\u679c\u4fe1\u606f\u3002","title":"\u5f00\u53d1\u6269\u5c55"},{"location":"development/dev-api/#httprunner-class","text":"HttpRunner \u4ee5 \u7c7b\uff08class\uff09 \u7684\u5f62\u5f0f\u5bf9\u5916\u63d0\u4f9b\u8c03\u7528\u652f\u6301\uff0c\u7c7b\u540d\b\u4e3a HttpRunner \uff0c\u5bfc\u5165\u65b9\u5f0f\u5982\u4e0b\uff1a from httprunner.api import HttpRunner","title":"HttpRunner class"},{"location":"development/dev-api/#_2","text":"HttpRunner \u5185\u90e8\b\u7528\u4e8e\u9a71\u52a8\u6d4b\u8bd5\u6267\u884c\u7684\u662f unittest.TextTestRunner \uff0c\u5728\u521d\u59cb\u5316 HttpRunner \u65f6\u53ef\u4ee5\u4f7f\u7528 TextTestRunner \u7684\u6240\u6709\u53ef\u7528\u53c2\u6570\uff08\u8be6\u60c5\u53ef\u9605\u8bfb \u5b98\u65b9\u6587\u6863 \uff09\u3002\u9664\u6b64\u4e4b\u5916\uff0c HttpRunner \u8fd8\u989d\u5916\u652f\u6301\u4e00\u4e2a\u53c2\u6570\uff0c http_client_session \uff0c\u53ef\u7528\u4e8e\u6307\u5b9a\u4e0d\u540c\u7684\u5ba2\u6237\u7aef\u7c7b\u578b\u3002 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u521d\u59cb\u5316 HttpRunner \u65f6\u5e38\u7528\u7684\u53c2\u6570\u6709\u5982\u4e0b\u51e0\u4e2a\uff1a resultclass : HtmlTestResult/TextTestResult\uff0c\u9ed8\u8ba4\u503c\u4e3a HtmlTestResult failfast : \u8bbe\u7f6e\u4e3a True \u65f6\uff0c\u6d4b\u8bd5\u5728\u9996\u6b21\u9047\u5230\u9519\u8bef\u6216\u5931\u8d25\u65f6\u4f1a\u505c\u6b62\u8fd0\u884c\uff1b\u9ed8\u8ba4\u503c\u4e3a False http_client_session : \u4f20\u5165 requests.Session() \u65f6\u8fdb\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff08\u9ed8\u8ba4\uff09\uff0c\u4f20\u5165 locust.client.Session() \u65f6\u8fdb\u884c\u6027\u80fd\u6d4b\u8bd5 \u4f8b\u5982\uff0c\u5982\u9700\u521d\u59cb\u5316 HttpRunner \u65f6\u8bbe\u7f6e failfast \u4e3a False\uff0c\b\u521d\u59cb\u5316\u65b9\u5f0f\u5982\u4e0b\u6240\u793a\uff1a from httprunner.api import HttpRunner runner = HttpRunner ( failfast = False )","title":"\u53ef\u7528\u521d\u59cb\u5316\u53c2\u6570"},{"location":"development/dev-api/#_3","text":"\u5728 HttpRunner \u4e2d\uff0c\u5bf9\u5916\u63d0\u4f9b\u4e86\u4e24\u4e2a\u65b9\u6cd5\uff1a run : \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b gen_html_report : \u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a","title":"\b\u53ef\u7528\u8c03\u7528\u65b9\u6cd5"},{"location":"development/dev-api/#_4","text":"\u5728 HttpRunner \u4e2d\uff0c\u5bf9\u5916\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5c5e\u6027\uff1a summary : \u6d4b\u8bd5\u6267\u884c\u7ed3\u679c \u8be5\u5c5e\u6027\u9700\u8981\u5728\u8c03\u7528 run \u65b9\u6cd5\u540e\u83b7\u53d6\u3002","title":"\u53ef\u7528\u5c5e\u6027"},{"location":"development/dev-api/#_5","text":"HttpRunner \u7684 run \u65b9\u6cd5\u6709\u4e09\u4e2a\u53c2\u6570\uff1a path_or_testcases : \u6307\u5b9a\u8981\u8fd0\u884c\u7684\u6d4b\u8bd5\u7528\u4f8b\uff1b\u652f\u6301\u4f20\u5165\u4e24\u7c7b\u53c2\u6570\uff0cYAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\uff0c\u6216\u8005\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\uff1b dot_env_path \uff08\u53ef\u9009\uff09: \u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u9ed8\u8ba4\u503c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e2d\u7684 .env \u6587\u4ef6 mapping \uff08\u53ef\u9009\uff09: \u53d8\u91cf\u6620\u5c04\uff0c\u53ef\u7528\u4e8e\u5bf9\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\u3002","title":"\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b"},{"location":"development/dev-api/#_6","text":"\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u652f\u6301\u4e09\u79cd\u5f62\u5f0f\uff1a YAML/JSON \u6587\u4ef6\u8def\u5f84\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u5305\u542b YAML/JSON \u6587\u4ef6\u7684\u6587\u4ef6\u5939\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u6587\u4ef6\u8def\u5f84\u548c\u6587\u4ef6\u5939\u8def\u5f84\u7684\u6df7\u5408\u60c5\u51b5\uff08list/set\uff09 # \u6587\u4ef6\u8def\u5f84 runner . run ( \"docs/data/demo-quickstart-2.yml\" ) # \u6587\u4ef6\u5939\u8def\u5f84 runner . run ( \"docs/data/\" ) # \u6df7\u5408\u60c5\u51b5 runner . run ([ \"docs/data/\" , \"files/demo-quickstart-2.yml\" ]) \u5982\u9700\u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u6216\u8005\u9700\u8981\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\uff0c\u5219\u53ef\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\u3002 # dot_env_path runner . run ( \"docs/data/demo-quickstart-2.yml\" , dot_env_path = \"/path/to/.env\" ) # mapping override_mapping = { \"device_sn\" : \"XXX\" } runner . run ( \"docs/data/demo-quickstart-2.yml\" , mapping = override_mapping )","title":"\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84"},{"location":"development/dev-api/#_7","text":"\u9664\u4e86\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\uff0c\u8fd8\u53ef\u4ee5\u76f4\u63a5\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u3002 \u4ee5 demo-quickstart-2.yml \u4e3a\u4f8b\uff0c\u5bf9\u5e94\u7684\u6570\u636e\u7ed3\u6784\u4f53\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { \"name\" : \"testcase description\" , \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" } }, \"variables\" : [], \"output\" : [ \"token\" ], \"path\" : \"/abs-path/to/demo-quickstart-2.yml\" , \"refs\" : { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } }, \"teststeps\" : [ { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" }, \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ] }, { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" }, \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [ { \"eq\" : [ \"status_code\" , 201 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]} ] } ] }, { ... } # another testcase ] \u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u65f6\uff0c\u652f\u6301\u4f20\u5165\u5355\u4e2a\u7ed3\u6784\u4f53\uff08dict\uff09\uff0c\u6216\u8005\u591a\u4e2a\u7ed3\u6784\u4f53\uff08list of dict\uff09\u3002 # \u8fd0\u884c\u5355\u4e2a\u7ed3\u6784\u4f53 runner . run ( testcase ) # \u8fd0\u884c\u591a\u4e2a\u7ed3\u6784\u4f53 runner . run ([ testcase1 , testcase2 ])","title":"\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53"},{"location":"development/dev-api/#debugtalkpy-env","text":"\b\u901a\u8fc7\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\bHttpRunner \u4f1a\u81ea\u52a8\u4ee5\b\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u4e3a\u8d77\u70b9\uff0c\u5411\u4e0a\u641c\u7d22 debugtalk.py \u6587\u4ef6\uff0c\u5e76\u5c06 debugtalk.py \u6587\u4ef6\u6240\u5728\u7684\u6587\u4ef6\u76ee\u5f55\u4f5c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u3002 \u540c\u65f6\uff0cHttpRunner \u4f1a\u5728\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e0b\b\b\u641c\u7d22 .env \u6587\u4ef6\uff0c\u4ee5\u53ca api \u548c testcases \u6587\u4ef6\u5939\uff0c\u5e76\u81ea\u52a8\u8fdb\u884c\u52a0\u8f7d\u3002 \u6700\u7ec8\u52a0\u8f7d\u5f97\u5230\u7684\u5b58\u50a8\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } \u5176\u4e2d\uff0c env \u5bf9\u5e94\u7684\u662f .env \u6587\u4ef6\u4e2d\u7684\u73af\u5883\u53d8\u91cf\uff0c debugtalk \u5bf9\u5e94\u7684\u662f debugtalk.py \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u548c\u51fd\u6570\uff0c def-api \u5bf9\u5e94\u7684\u662f api \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u63a5\u53e3\u63cf\u8ff0\uff0c def-testcase \u5bf9\u5e94\u7684\u662f testcases \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u6d4b\u8bd5\u7528\u4f8b\u3002 \u901a\u8fc7\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u6267\u884c\u6d4b\u8bd5\u65f6\uff0c\u4f20\u5165\u7684\u6570\u636e\u5e94\u5305\u542b\u6240\u6709\u4fe1\u606f\uff0c\u5305\u62ec debugtalk.py \u3001 .env \u3001\u4f9d\u8d56\u7684 api \u548c \u6d4b\u8bd5\u7528\u4f8b\u7b49\uff1b\u56e0\u6b64\u4e5f\u65e0\u9700\u518d\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\uff0c\u6240\u6709\u4fe1\u606f\u90fd\u8981\u901a\u8fc7 refs \u4f20\u5165\u3002","title":"\u52a0\u8f7d debugtalk.py && .env"},{"location":"development/dev-api/#_8","text":"\u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u901a\u8fc7 summary \u5c5e\u6027\u53ef\u83b7\u53d6\u8be6\u5c3d\u7684\u8fd0\u884c\u7ed3\u679c\u6570\u636e\u3002 # get result summary summary = runner . summary \u5176\u6570\u636e\u7ed3\u6784\u4e3a\uff1a { \"success\" : true , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"platform\" : { \"httprunner_version\" : \"1.5.14\" , \"python_version\" : \"CPython 3.6.5+\" , \"platform\" : \"Darwin-17.6.0-x86_64-i386-64bit\" }, \"details\" : [ { \"success\" : true , \"name\" : \"testcase description\" , \"base_url\" : \"\" , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"records\" : [ { \"name\" : \"/api/get-token\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" , \"Content-Length\" : \"52\" }, \"start_timestamp\" : 1538449655.944801 , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }, \"body\" : b' { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } ' }, \"response\" : { \"status_code\" : 200 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"46\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 46 , \"response_time_ms\" : 12.87 , \"elapsed_ms\" : 6.955 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"reason\" : \"OK\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"json\" : { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 200 , \"comparator\" : \"eq\" , \"check_value\" : 200 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" } ] } }, { \"name\" : \"/api/users/1000\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"CcQ7dBjZZbjIXRkG\" , \"Content-Length\" : \"39\" }, \"start_timestamp\" : 1538449655.958944 , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }, \"body\" : b' { \"name\" : \"user1\" , \"password\" : \"123456\" } ' }, \"response\" : { \"status_code\" : 201 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"54\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 54 , \"response_time_ms\" : 3.34 , \"elapsed_ms\" : 2.16 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"reason\" : \"CREATED\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"json\" : { \"success\" : true , \"msg\" : \"user created successfully.\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 201 , \"comparator\" : \"eq\" , \"check_value\" : 201 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" }, { \"check\" : \"content.msg\" , \"expect\" : \"user created successfully.\" , \"comparator\" : \"eq\" , \"check_value\" : \"user created successfully.\" , \"check_result\" : \"pass\" } ] } } ], \"in_out\" : { \"in\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"out\" : { \"token\" : \"CcQ7dBjZZbjIXRkG\" } } } ] }","title":"\u8fd4\u56de\u8be6\u7ec6\u6d4b\u8bd5\u7ed3\u679c\u6570\u636e"},{"location":"development/dev-api/#html","text":"\u5982\u9700\u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u53ef\u8c03\u7528 gen_html_report \u65b9\u6cd5\u3002 # generate html report runner . gen_html_report ( html_report_name = \"demo\" , html_report_template = \"/path/to/custom_report_template\" ) # => reports/demo/demo-1532078874.html \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u90e8\u5206\u3002","title":"\u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a"},{"location":"examples/testerhome-login/","text":"\u6848\u4f8b\u4ecb\u7ecd \u00b6 \u901a\u8fc7\u63a5\u53e3\u81ea\u52a8\u5316\u5b9e\u73b0 TesterHome \u7684\u767b\u5f55\u9000\u51fa\u529f\u80fd\u3002 \u529f\u80fd\u63cf\u8ff0\uff1a \u8fdb\u5165 \u767b\u5f55\u9875\u9762 \u8f93\u5165\u8d26\u53f7\u548c\u5bc6\u7801 \u70b9\u51fb\u3010Sign In\u3011\u8fdb\u884c\u767b\u5f55 \u51c6\u5907\u5de5\u4f5c \u00b6 \u6293\u5305\u751f\u6210 HAR \u6587\u4ef6 \u00b6 \u5728\u6d4f\u89c8\u5668\u4e2d\u4eba\u5de5\u8fdb\u884c\u767b\u5f55\u64cd\u4f5c\uff0c\u540c\u65f6\u4f7f\u7528\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u3002\u6293\u5305\u65f6\u5efa\u8bae\u4f7f\u7528\u8fc7\u6ee4\u5668\uff08Filter\uff09\uff0c\u5e38\u7528\u7684\u505a\u6cd5\u662f\u91c7\u7528\u88ab\u6d4b\u7cfb\u7edf\u7684 host\uff0c\u5c06\u65e0\u5173\u8bf7\u6c42\u8fc7\u6ee4\u6389\u3002 \u9009\u62e9\u9700\u8981\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u7684\u8bf7\u6c42\uff0c\u5bfc\u51fa\u4e3a HTTP Archive (.har) \u683c\u5f0f\u7684\u6587\u4ef6\u3002 \u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e har2case \u547d\u4ee4\uff0c\u4f7f\u7528\u8be5\u547d\u4ee4\u53ef\u5c06 HAR \u6570\u636e\u5305\u8f6c\u6362\u4e3a HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/testerhome-login.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/testerhome-login.yml \u751f\u6210\u7684\u6d4b\u8bd5\u7528\u4f8b\u5185\u5bb9\u5982\u4e0b\uff1a \u70b9\u51fb\u67e5\u770b - config : name : testcase description variables : {} - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] - test : name : /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png request : headers : User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , image/png ] - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/javascript; charset=utf-8 ] - test : name : / request : headers : If-None-Match : W/\"bad62c68dac27b01151516aad5c7f0be\" Turbolinks-Referrer : https://testerhome.com/account/sign_in User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/ validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e hrun \u547d\u4ee4\uff0c\u8be5\u547d\u4ee4\u662f HttpRunner \u7684\u6838\u5fc3\u547d\u4ee4\uff0c\u7528\u4e8e\u8fd0\u884c HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u5c1d\u8bd5\u8fd0\u884c\u4e00\u6b21\uff0c\u5927\u591a\u6570\u60c5\u51b5\uff0c\u5982\u679c\u88ab\u6d4b\u573a\u666f\u4e2d\u4e0d\u5b58\u5728\u5173\u8054\u7684\u60c5\u51b5\uff0c\u662f\u53ef\u4ee5\u76f4\u63a5\u8fd0\u884c\u6210\u529f\u7684\u3002 $ hrun docs/data/testerhome-login.yml --failfast --log-level info INFO Start to run testcase: testcase description /account/sign_in INFO GET https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 189 .66 ms, response_length: 12584 bytes . /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO GET https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO status_code: 200 , response_time ( ms ) : 83 .98 ms, response_length: 15229 bytes . /account/sign_in INFO POST https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 172 .8 ms, response_length: 89 bytes . / INFO GET https://testerhome.com/ INFO status_code: 200 , response_time ( ms ) : 257 .41 ms, response_length: 52463 bytes . ---------------------------------------------------------------------- Ran 4 tests in 0 .722s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1555662601.html \u6bd4\u8f83\u5e78\u8fd0\uff0c\u811a\u672c\u5728\u6ca1\u6709\u505a\u4efb\u4f55\u4fee\u6539\u7684\u60c5\u51b5\u4e0b\u8fd0\u884c\u6210\u529f\u4e86\u3002 \u8c03\u8bd5 & \u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u867d\u7136\u811a\u672c\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ba1\u7406\u548c\u7ef4\u62a4\u811a\u672c\uff0c\u9700\u8981\u5bf9\u811a\u672c\u8fdb\u884c\u4f18\u5316\u8c03\u6574\u3002 \u5173\u8054\u5904\u7406 \u00b6 \u67e5\u770b\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\uff0c\u53ef\u4ee5\u770b\u5230\u5728\u53d1\u8d77\u767b\u5f55\u8bf7\u6c42\u65f6\u5305\u542b\u4e86 X-CSRF-Token \uff0c\u5982\u679c\u719f\u6089\u7f51\u7edc\u4fe1\u606f\u5b89\u5168\u7684\u57fa\u7840\u77e5\u8bc6\uff0c\u5c31\u4f1a\u8054\u60f3\u5230\u8be5\u5b57\u6bb5\u662f\u52a8\u6001\u53d8\u5316\u7684\uff0c\u6bcf\u6b21\u90fd\u662f\u5148\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u81f3\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u5728\u540e\u7eed\u53d1\u8d77\u8bf7\u6c42\u65f6\u9700\u8981\u643a\u5e26\u8be5\u5b57\u6bb5\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u867d\u7136\u5f53\u524d\u76f4\u63a5\u8fd0\u884c\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\u4e5f\u662f\u6210\u529f\u7684\uff0c\u4f46\u5f88\u6709\u53ef\u80fd\u5728\u8fc7\u4e86\u4e00\u6bb5\u65f6\u95f4\u540e\uff0c X-CSRF-Token \u5931\u6548\uff0c\u811a\u672c\u4e5f\u5c31\u65e0\u6cd5\u518d\u6210\u529f\u8fd0\u884c\u4e86\u3002\u56e0\u6b64\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\uff0c\u8be5\u5b57\u6bb5\u4e0d\u80fd\u5199\u6b7b\u4e3a\u6293\u5305\u65f6\u83b7\u53d6\u7684\u503c\uff0c\u800c\u662f\u8981\u6bcf\u6b21\u52a8\u6001\u5730\u4ece\u524d\u9762\u7684\u63a5\u53e3\u54cd\u5e94\u4e2d\u83b7\u53d6\u3002 \u90a3\u8981\u600e\u4e48\u786e\u5b9a\u8be5\u5b57\u6bb5\u662f\u5728\u4e4b\u524d\u7684\u54ea\u4e2a\u63a5\u53e3\u4e2d\u8fd4\u56de\u7684\u5462\uff1f \u64cd\u4f5c\u65b9\u5f0f\u4e5f\u5f88\u7b80\u5355\uff0c\u53ef\u4ee5\u5728\u6293\u5305\u5de5\u5177\u4e2d\u5bf9\u8be5\u5b57\u6bb5\u8fdb\u884c\u641c\u7d22\uff0c\u7279\u522b\u5730\uff0c\u641c\u7d22\u8303\u56f4\u9650\u5b9a\u4e3a\u54cd\u5e94\u5185\u5bb9\uff08Response Header\u3001Response Body\uff09\u3002 \u5373\u53ef\u641c\u7d22\u5f97\u5230\u8be5\u5b57\u6bb5\u662f\u5728\u54ea\u4e2a\u63a5\u53e3\u4e2d\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u503c\u5ba2\u6237\u7aef\u7684\u3002 \u6709\u65f6\u5019\u53ef\u80fd\u641c\u7d22\u4f1a\u5f97\u5230\u591a\u4e2a\u7ed3\u679c\uff0c\u90a3\u4e48\u5728\u786e\u5b9a\u662f\u4f7f\u7528\u54ea\u4e2a\u63a5\u53e3\u54cd\u5e94\u7684\u65f6\u5019\uff0c\u9075\u5faa\u4e24\u4e2a\u539f\u5219\u5373\u53ef\uff1a \u54cd\u5e94\u4e00\u5b9a\u662f\u51fa\u73b0\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d \u5982\u679c\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d\u5b58\u5728\u591a\u4e2a\u63a5\u53e3\u5747\u6709\u6b64\u8fd4\u56de\uff0c\u90a3\u4e48\u53d6\u6700\u9760\u8fd1\u5f53\u524d\u63a5\u53e3\u7684\u5373\u53ef \u901a\u8fc7\u524d\u9762\u7684\u641c\u7d22\u53ef\u77e5\uff0c X-CSRF-Token \u7684\u503c\u662f\u5728\u7b2c\u4e00\u4e2a\u63a5\u53e3\u4e2d\u54cd\u5e94\u8fd4\u56de\u7684\u3002 \u786e\u5b9a\u51fa\u5177\u4f53\u7684\u63a5\u53e3\u540e\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u4ece\u8be5\u63a5\u53e3\u4f7f\u7528 extract \u63d0\u53d6\u5bf9\u5e94\u7684\u5b57\u6bb5\uff0c\u7136\u540e\u5728\u540e\u7eed\u63a5\u53e3\u4e2d\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u3002 \u5728\u5f53\u524d\u6848\u4f8b\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a HTML \u9875\u9762\uff0c\u8981\u63d0\u53d6\u5b57\u6bb5\u53ef\u4ee5\u4f7f\u7528\u6b63\u5219\u5339\u914d\u7684\u65b9\u5f0f\u3002\u5177\u4f53\u7684\u505a\u6cd5\u5c31\u662f\u6307\u5b9a\u76ee\u6807\u5b57\u6bb5\u7684\u5de6\u53f3\u8fb9\u754c\uff0c\u76ee\u6807\u5b57\u6bb5\u4f7f\u7528 (.*) \u5339\u914d\u83b7\u53d6\u3002 - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in extract : X_CSRF_Token : validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u7136\u540e\uff0c\u5728\u540e\u7eed\u4f7f\u7528\u5230\u8be5\u5b57\u6bb5\u7684\u63a5\u53e3\u4e2d\uff0c\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u5373\u53ef\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : $X_CSRF_Token X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ]","title":"TesterHome \u767b\u5f55"},{"location":"examples/testerhome-login/#_1","text":"\u901a\u8fc7\u63a5\u53e3\u81ea\u52a8\u5316\u5b9e\u73b0 TesterHome \u7684\u767b\u5f55\u9000\u51fa\u529f\u80fd\u3002 \u529f\u80fd\u63cf\u8ff0\uff1a \u8fdb\u5165 \u767b\u5f55\u9875\u9762 \u8f93\u5165\u8d26\u53f7\u548c\u5bc6\u7801 \u70b9\u51fb\u3010Sign In\u3011\u8fdb\u884c\u767b\u5f55","title":"\u6848\u4f8b\u4ecb\u7ecd"},{"location":"examples/testerhome-login/#_2","text":"","title":"\u51c6\u5907\u5de5\u4f5c"},{"location":"examples/testerhome-login/#har","text":"\u5728\u6d4f\u89c8\u5668\u4e2d\u4eba\u5de5\u8fdb\u884c\u767b\u5f55\u64cd\u4f5c\uff0c\u540c\u65f6\u4f7f\u7528\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u3002\u6293\u5305\u65f6\u5efa\u8bae\u4f7f\u7528\u8fc7\u6ee4\u5668\uff08Filter\uff09\uff0c\u5e38\u7528\u7684\u505a\u6cd5\u662f\u91c7\u7528\u88ab\u6d4b\u7cfb\u7edf\u7684 host\uff0c\u5c06\u65e0\u5173\u8bf7\u6c42\u8fc7\u6ee4\u6389\u3002 \u9009\u62e9\u9700\u8981\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u7684\u8bf7\u6c42\uff0c\u5bfc\u51fa\u4e3a HTTP Archive (.har) \u683c\u5f0f\u7684\u6587\u4ef6\u3002","title":"\u6293\u5305\u751f\u6210 HAR \u6587\u4ef6"},{"location":"examples/testerhome-login/#_3","text":"\u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e har2case \u547d\u4ee4\uff0c\u4f7f\u7528\u8be5\u547d\u4ee4\u53ef\u5c06 HAR \u6570\u636e\u5305\u8f6c\u6362\u4e3a HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/testerhome-login.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/testerhome-login.yml \u751f\u6210\u7684\u6d4b\u8bd5\u7528\u4f8b\u5185\u5bb9\u5982\u4e0b\uff1a \u70b9\u51fb\u67e5\u770b - config : name : testcase description variables : {} - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] - test : name : /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png request : headers : User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , image/png ] - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/javascript; charset=utf-8 ] - test : name : / request : headers : If-None-Match : W/\"bad62c68dac27b01151516aad5c7f0be\" Turbolinks-Referrer : https://testerhome.com/account/sign_in User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/ validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ]","title":"\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b"},{"location":"examples/testerhome-login/#_4","text":"\u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e hrun \u547d\u4ee4\uff0c\u8be5\u547d\u4ee4\u662f HttpRunner \u7684\u6838\u5fc3\u547d\u4ee4\uff0c\u7528\u4e8e\u8fd0\u884c HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u5c1d\u8bd5\u8fd0\u884c\u4e00\u6b21\uff0c\u5927\u591a\u6570\u60c5\u51b5\uff0c\u5982\u679c\u88ab\u6d4b\u573a\u666f\u4e2d\u4e0d\u5b58\u5728\u5173\u8054\u7684\u60c5\u51b5\uff0c\u662f\u53ef\u4ee5\u76f4\u63a5\u8fd0\u884c\u6210\u529f\u7684\u3002 $ hrun docs/data/testerhome-login.yml --failfast --log-level info INFO Start to run testcase: testcase description /account/sign_in INFO GET https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 189 .66 ms, response_length: 12584 bytes . /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO GET https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO status_code: 200 , response_time ( ms ) : 83 .98 ms, response_length: 15229 bytes . /account/sign_in INFO POST https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 172 .8 ms, response_length: 89 bytes . / INFO GET https://testerhome.com/ INFO status_code: 200 , response_time ( ms ) : 257 .41 ms, response_length: 52463 bytes . ---------------------------------------------------------------------- Ran 4 tests in 0 .722s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1555662601.html \u6bd4\u8f83\u5e78\u8fd0\uff0c\u811a\u672c\u5728\u6ca1\u6709\u505a\u4efb\u4f55\u4fee\u6539\u7684\u60c5\u51b5\u4e0b\u8fd0\u884c\u6210\u529f\u4e86\u3002","title":"\u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b"},{"location":"examples/testerhome-login/#_5","text":"\u867d\u7136\u811a\u672c\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ba1\u7406\u548c\u7ef4\u62a4\u811a\u672c\uff0c\u9700\u8981\u5bf9\u811a\u672c\u8fdb\u884c\u4f18\u5316\u8c03\u6574\u3002","title":"\u8c03\u8bd5 & \u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b"},{"location":"examples/testerhome-login/#_6","text":"\u67e5\u770b\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\uff0c\u53ef\u4ee5\u770b\u5230\u5728\u53d1\u8d77\u767b\u5f55\u8bf7\u6c42\u65f6\u5305\u542b\u4e86 X-CSRF-Token \uff0c\u5982\u679c\u719f\u6089\u7f51\u7edc\u4fe1\u606f\u5b89\u5168\u7684\u57fa\u7840\u77e5\u8bc6\uff0c\u5c31\u4f1a\u8054\u60f3\u5230\u8be5\u5b57\u6bb5\u662f\u52a8\u6001\u53d8\u5316\u7684\uff0c\u6bcf\u6b21\u90fd\u662f\u5148\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u81f3\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u5728\u540e\u7eed\u53d1\u8d77\u8bf7\u6c42\u65f6\u9700\u8981\u643a\u5e26\u8be5\u5b57\u6bb5\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u867d\u7136\u5f53\u524d\u76f4\u63a5\u8fd0\u884c\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\u4e5f\u662f\u6210\u529f\u7684\uff0c\u4f46\u5f88\u6709\u53ef\u80fd\u5728\u8fc7\u4e86\u4e00\u6bb5\u65f6\u95f4\u540e\uff0c X-CSRF-Token \u5931\u6548\uff0c\u811a\u672c\u4e5f\u5c31\u65e0\u6cd5\u518d\u6210\u529f\u8fd0\u884c\u4e86\u3002\u56e0\u6b64\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\uff0c\u8be5\u5b57\u6bb5\u4e0d\u80fd\u5199\u6b7b\u4e3a\u6293\u5305\u65f6\u83b7\u53d6\u7684\u503c\uff0c\u800c\u662f\u8981\u6bcf\u6b21\u52a8\u6001\u5730\u4ece\u524d\u9762\u7684\u63a5\u53e3\u54cd\u5e94\u4e2d\u83b7\u53d6\u3002 \u90a3\u8981\u600e\u4e48\u786e\u5b9a\u8be5\u5b57\u6bb5\u662f\u5728\u4e4b\u524d\u7684\u54ea\u4e2a\u63a5\u53e3\u4e2d\u8fd4\u56de\u7684\u5462\uff1f \u64cd\u4f5c\u65b9\u5f0f\u4e5f\u5f88\u7b80\u5355\uff0c\u53ef\u4ee5\u5728\u6293\u5305\u5de5\u5177\u4e2d\u5bf9\u8be5\u5b57\u6bb5\u8fdb\u884c\u641c\u7d22\uff0c\u7279\u522b\u5730\uff0c\u641c\u7d22\u8303\u56f4\u9650\u5b9a\u4e3a\u54cd\u5e94\u5185\u5bb9\uff08Response Header\u3001Response Body\uff09\u3002 \u5373\u53ef\u641c\u7d22\u5f97\u5230\u8be5\u5b57\u6bb5\u662f\u5728\u54ea\u4e2a\u63a5\u53e3\u4e2d\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u503c\u5ba2\u6237\u7aef\u7684\u3002 \u6709\u65f6\u5019\u53ef\u80fd\u641c\u7d22\u4f1a\u5f97\u5230\u591a\u4e2a\u7ed3\u679c\uff0c\u90a3\u4e48\u5728\u786e\u5b9a\u662f\u4f7f\u7528\u54ea\u4e2a\u63a5\u53e3\u54cd\u5e94\u7684\u65f6\u5019\uff0c\u9075\u5faa\u4e24\u4e2a\u539f\u5219\u5373\u53ef\uff1a \u54cd\u5e94\u4e00\u5b9a\u662f\u51fa\u73b0\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d \u5982\u679c\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d\u5b58\u5728\u591a\u4e2a\u63a5\u53e3\u5747\u6709\u6b64\u8fd4\u56de\uff0c\u90a3\u4e48\u53d6\u6700\u9760\u8fd1\u5f53\u524d\u63a5\u53e3\u7684\u5373\u53ef \u901a\u8fc7\u524d\u9762\u7684\u641c\u7d22\u53ef\u77e5\uff0c X-CSRF-Token \u7684\u503c\u662f\u5728\u7b2c\u4e00\u4e2a\u63a5\u53e3\u4e2d\u54cd\u5e94\u8fd4\u56de\u7684\u3002 \u786e\u5b9a\u51fa\u5177\u4f53\u7684\u63a5\u53e3\u540e\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u4ece\u8be5\u63a5\u53e3\u4f7f\u7528 extract \u63d0\u53d6\u5bf9\u5e94\u7684\u5b57\u6bb5\uff0c\u7136\u540e\u5728\u540e\u7eed\u63a5\u53e3\u4e2d\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u3002 \u5728\u5f53\u524d\u6848\u4f8b\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a HTML \u9875\u9762\uff0c\u8981\u63d0\u53d6\u5b57\u6bb5\u53ef\u4ee5\u4f7f\u7528\u6b63\u5219\u5339\u914d\u7684\u65b9\u5f0f\u3002\u5177\u4f53\u7684\u505a\u6cd5\u5c31\u662f\u6307\u5b9a\u76ee\u6807\u5b57\u6bb5\u7684\u5de6\u53f3\u8fb9\u754c\uff0c\u76ee\u6807\u5b57\u6bb5\u4f7f\u7528 (.*) \u5339\u914d\u83b7\u53d6\u3002 - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in extract : X_CSRF_Token : validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u7136\u540e\uff0c\u5728\u540e\u7eed\u4f7f\u7528\u5230\u8be5\u5b57\u6bb5\u7684\u63a5\u53e3\u4e2d\uff0c\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u5373\u53ef\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : $X_CSRF_Token X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ]","title":"\u5173\u8054\u5904\u7406"},{"location":"prepare/dot-env/","text":"\u73af\u5883\u53d8\u91cf\u7684\u4f5c\u7528 \u00b6 \u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u6709\u65f6\u9700\u8981\u501f\u52a9\u73af\u5883\u53d8\u91cf\u5b9e\u73b0\u67d0\u4e9b\u7279\u5b9a\u7684\u76ee\u7684\uff0c\u5e38\u89c1\u7684\u573a\u666f\u5305\u62ec\uff1a \u5207\u6362\u6d4b\u8bd5\u73af\u5883 \u5207\u6362\u6d4b\u8bd5\u914d\u7f6e \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u4ece \u4fe1\u606f\u5b89\u5168 \u7684\u89d2\u5ea6\u51fa\u53d1\uff09 \u8bbe\u7f6e\u73af\u5883\u53d8\u91cf \u00b6 \u5728\u7ec8\u7aef\u4e2d\u9884\u8bbe\u73af\u5883\u53d8\u91cf \u00b6 \u4f7f\u7528\u73af\u5883\u53d8\u91cf\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5728\u7cfb\u7edf\u4e2d\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u540d\u79f0\u548c\u503c\uff0c\u4f20\u7edf\u7684\u65b9\u5f0f\u4e3a\u4f7f\u7528 export \u547d\u4ee4\uff08Windows\u7cfb\u7edf\u4e2d\u4f7f\u7528 set \u547d\u4ee4\uff09\uff1a $ export UserName = admin $ echo $UserName admin $ export Password = 123456 $ echo $Password 123456 \u7136\u540e\uff0c\u5728\u7a0b\u5e8f\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u7cfb\u7edf\u4e2d\u7684\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u3002 $ python >>> import os >>> os.environ [ \"UserName\" ] 'admin' \u901a\u8fc7 .env \u6587\u4ef6\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf \u00b6 \u9664\u4e86\u8fd9\u79cd\u65b9\u5f0f\uff0cHttpRunner \u8fd8\u501f\u9274\u4e86 pipenv \u52a0\u8f7d .env \u7684\u65b9\u5f0f \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e2d\uff0c\u521b\u5efa .env \u6587\u4ef6\uff0c\u5e76\u5c06\u654f\u611f\u6570\u636e\u4fe1\u606f\u653e\u7f6e\u5230\u5176\u4e2d\uff0c\u5b58\u50a8\u91c7\u7528 name=value \u7684\u683c\u5f0f\uff1a $ cat .env UserName = admin Password = 123456 PROJECT_KEY = ABCDEFGH \u540c\u65f6\uff0c .env \u6587\u4ef6\u4e0d\u5e94\u8be5\u6dfb\u52a0\u5230\u4ee3\u7801\u4ed3\u5e93\u4e2d\uff0c\u5efa\u8bae\u5c06 .env \u52a0\u5165\u5230 .gitignore \u4e2d\u3002 HttpRunner \u8fd0\u884c\u65f6\uff0c\u4f1a\u81ea\u52a8\u5c06 .env \u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u52a0\u8f7d\u5230\u8fd0\u884c\u65f6\uff08RunTime\uff09\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u7136\u540e\u5728\u8fd0\u884c\u65f6\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u4e86\u3002 \u82e5\u9700\u52a0\u8f7d\u4e0d\u4f4d\u4e8e\u81ea\u52a8\u5316\u9879\u76ee\u6839\u76ee\u5f55\u4e2d\u7684 .env \uff0c\u6216\u8005\u5176\u5b83\u540d\u79f0\u7684 .env \u6587\u4ef6\uff08\u4f8b\u5982 production.env \uff09\uff0c\u53ef\u4ee5\u91c7\u7528 --dot-env-path \u53c2\u6570\u6307\u5b9a\u6587\u4ef6\u8def\u5f84\uff1a $ hrun /path/to/testcase.yml --dot-env-path /path/to/.env --log-level debug INFO Loading environment variables from /path/to/.env DEBUG Loaded variable: UserName DEBUG Loaded variable: Password DEBUG Loaded variable: PROJECT_KEY ... \u5f15\u7528\u73af\u5883\u53d8\u91cf \u00b6 \u5728 HttpRunner \u4e2d\u5185\u7f6e\u4e86\u51fd\u6570 environ \uff08\u7b80\u79f0 ENV \uff09\uff0c\u53ef\u7528\u4e8e\u5728 YAML/JSON \u811a\u672c\u4e2d\u76f4\u63a5\u5f15\u7528\u73af\u5883\u53d8\u91cf\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${ENV(Password)} validate : - eq : [ status_code , 200 ] \u82e5\u8fd8\u9700\u5bf9\u8bfb\u53d6\u7684\u73af\u5883\u53d8\u91cf\u505a\u8fdb\u4e00\u6b65\u5904\u7406\uff0c\u5219\u53ef\u4ee5\u5728 debugtalk.py \u901a\u8fc7 Python \u5185\u7f6e\u7684\u51fd\u6570 os.environ \u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e\u518d\u5b9e\u73b0\u5904\u7406\u903b\u8f91\u3002 \u4f8b\u5982\uff0c\u82e5\u53d1\u8d77\u8bf7\u6c42\u7684\u5bc6\u7801\u9700\u8981\u5148\u4e0e\u5bc6\u94a5\u8fdb\u884c\u62fc\u63a5\u5e76\u751f\u6210 MD5\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u6587\u4ef6\u4e2d\u5b9e\u73b0\u5982\u4e0b\u51fd\u6570\uff1a import os def get_encrypt_password (): raw_passwd = os . environ [ \"Password\" ] PROJECT_KEY = os . environ [ \"PROJECT_KEY\" ]) password = ( raw_passwd + PROJECT_KEY ) . encode ( 'ascii' ) return hmac . new ( password , hashlib . sha1 ) . hexdigest () \u7136\u540e\uff0c\u5728 YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7 ${func()} \u7684\u65b9\u5f0f\u5f15\u7528\u73af\u5883\u53d8\u91cf\u7684\u503c\u4e86\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${get_encrypt_password()} validate : - eq : [ status_code , 200 ]","title":"\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#_1","text":"\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u6709\u65f6\u9700\u8981\u501f\u52a9\u73af\u5883\u53d8\u91cf\u5b9e\u73b0\u67d0\u4e9b\u7279\u5b9a\u7684\u76ee\u7684\uff0c\u5e38\u89c1\u7684\u573a\u666f\u5305\u62ec\uff1a \u5207\u6362\u6d4b\u8bd5\u73af\u5883 \u5207\u6362\u6d4b\u8bd5\u914d\u7f6e \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u4ece \u4fe1\u606f\u5b89\u5168 \u7684\u89d2\u5ea6\u51fa\u53d1\uff09","title":"\u73af\u5883\u53d8\u91cf\u7684\u4f5c\u7528"},{"location":"prepare/dot-env/#_2","text":"","title":"\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#_3","text":"\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5728\u7cfb\u7edf\u4e2d\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u540d\u79f0\u548c\u503c\uff0c\u4f20\u7edf\u7684\u65b9\u5f0f\u4e3a\u4f7f\u7528 export \u547d\u4ee4\uff08Windows\u7cfb\u7edf\u4e2d\u4f7f\u7528 set \u547d\u4ee4\uff09\uff1a $ export UserName = admin $ echo $UserName admin $ export Password = 123456 $ echo $Password 123456 \u7136\u540e\uff0c\u5728\u7a0b\u5e8f\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u7cfb\u7edf\u4e2d\u7684\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u3002 $ python >>> import os >>> os.environ [ \"UserName\" ] 'admin'","title":"\u5728\u7ec8\u7aef\u4e2d\u9884\u8bbe\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#env","text":"\u9664\u4e86\u8fd9\u79cd\u65b9\u5f0f\uff0cHttpRunner \u8fd8\u501f\u9274\u4e86 pipenv \u52a0\u8f7d .env \u7684\u65b9\u5f0f \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e2d\uff0c\u521b\u5efa .env \u6587\u4ef6\uff0c\u5e76\u5c06\u654f\u611f\u6570\u636e\u4fe1\u606f\u653e\u7f6e\u5230\u5176\u4e2d\uff0c\u5b58\u50a8\u91c7\u7528 name=value \u7684\u683c\u5f0f\uff1a $ cat .env UserName = admin Password = 123456 PROJECT_KEY = ABCDEFGH \u540c\u65f6\uff0c .env \u6587\u4ef6\u4e0d\u5e94\u8be5\u6dfb\u52a0\u5230\u4ee3\u7801\u4ed3\u5e93\u4e2d\uff0c\u5efa\u8bae\u5c06 .env \u52a0\u5165\u5230 .gitignore \u4e2d\u3002 HttpRunner \u8fd0\u884c\u65f6\uff0c\u4f1a\u81ea\u52a8\u5c06 .env \u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u52a0\u8f7d\u5230\u8fd0\u884c\u65f6\uff08RunTime\uff09\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u7136\u540e\u5728\u8fd0\u884c\u65f6\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u4e86\u3002 \u82e5\u9700\u52a0\u8f7d\u4e0d\u4f4d\u4e8e\u81ea\u52a8\u5316\u9879\u76ee\u6839\u76ee\u5f55\u4e2d\u7684 .env \uff0c\u6216\u8005\u5176\u5b83\u540d\u79f0\u7684 .env \u6587\u4ef6\uff08\u4f8b\u5982 production.env \uff09\uff0c\u53ef\u4ee5\u91c7\u7528 --dot-env-path \u53c2\u6570\u6307\u5b9a\u6587\u4ef6\u8def\u5f84\uff1a $ hrun /path/to/testcase.yml --dot-env-path /path/to/.env --log-level debug INFO Loading environment variables from /path/to/.env DEBUG Loaded variable: UserName DEBUG Loaded variable: Password DEBUG Loaded variable: PROJECT_KEY ...","title":"\u901a\u8fc7 .env \u6587\u4ef6\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#_4","text":"\u5728 HttpRunner \u4e2d\u5185\u7f6e\u4e86\u51fd\u6570 environ \uff08\u7b80\u79f0 ENV \uff09\uff0c\u53ef\u7528\u4e8e\u5728 YAML/JSON \u811a\u672c\u4e2d\u76f4\u63a5\u5f15\u7528\u73af\u5883\u53d8\u91cf\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${ENV(Password)} validate : - eq : [ status_code , 200 ] \u82e5\u8fd8\u9700\u5bf9\u8bfb\u53d6\u7684\u73af\u5883\u53d8\u91cf\u505a\u8fdb\u4e00\u6b65\u5904\u7406\uff0c\u5219\u53ef\u4ee5\u5728 debugtalk.py \u901a\u8fc7 Python \u5185\u7f6e\u7684\u51fd\u6570 os.environ \u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e\u518d\u5b9e\u73b0\u5904\u7406\u903b\u8f91\u3002 \u4f8b\u5982\uff0c\u82e5\u53d1\u8d77\u8bf7\u6c42\u7684\u5bc6\u7801\u9700\u8981\u5148\u4e0e\u5bc6\u94a5\u8fdb\u884c\u62fc\u63a5\u5e76\u751f\u6210 MD5\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u6587\u4ef6\u4e2d\u5b9e\u73b0\u5982\u4e0b\u51fd\u6570\uff1a import os def get_encrypt_password (): raw_passwd = os . environ [ \"Password\" ] PROJECT_KEY = os . environ [ \"PROJECT_KEY\" ]) password = ( raw_passwd + PROJECT_KEY ) . encode ( 'ascii' ) return hmac . new ( password , hashlib . sha1 ) . hexdigest () \u7136\u540e\uff0c\u5728 YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7 ${func()} \u7684\u65b9\u5f0f\u5f15\u7528\u73af\u5883\u53d8\u91cf\u7684\u503c\u4e86\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${get_encrypt_password()} validate : - eq : [ status_code , 200 ]","title":"\u5f15\u7528\u73af\u5883\u53d8\u91cf"},{"location":"prepare/parameters/","text":"\u4ecb\u7ecd \u00b6 \u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u7ecf\u5e38\u4f1a\u9047\u5230\u5982\u4e0b\u573a\u666f\uff1a \u6d4b\u8bd5\u641c\u7d22\u529f\u80fd\uff0c\u53ea\u6709\u4e00\u4e2a\u641c\u7d22\u8f93\u5165\u6846\uff0c\u4f46\u6709 10 \u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u641c\u7d22\u5173\u952e\u5b57\uff1b \u6d4b\u8bd5\u8d26\u53f7\u767b\u5f55\u529f\u80fd\uff0c\u9700\u8981\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u6309\u7167\u7b49\u4ef7\u7c7b\u5212\u5206\u540e\u6709 20 \u79cd\u7ec4\u5408\u60c5\u51b5\u3002 \u8fd9\u91cc\u53ea\u662f\u968f\u610f\u627e\u4e86\u4e24\u4e2a\u5178\u578b\u7684\u4f8b\u5b50\uff0c\u76f8\u4fe1\u5927\u5bb6\u90fd\u6709\u9047\u5230\u8fc7\u5f88\u591a\u7c7b\u4f3c\u7684\u573a\u666f\u3002\u603b\u7ed3\u4e0b\u6765\uff0c\u5c31\u662f\u5728\u6211\u4eec\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u811a\u672c\u4e2d\u5b58\u5728\u53c2\u6570\uff0c\u5e76\u4e14\u6211\u4eec\u9700\u8981\u91c7\u7528\u4e0d\u540c\u7684\u53c2\u6570\u53bb\u8fd0\u884c\u3002 \u7ecf\u8fc7\u6982\u62ec\uff0c\u53c2\u6570\u57fa\u672c\u4e0a\u5206\u4e3a\u4e24\u79cd\u7c7b\u578b\uff1a \u5355\u4e2a\u72ec\u7acb\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e00\u79cd\u573a\u666f\uff0c\u6211\u4eec\u53ea\u9700\u8981\u53d8\u6362\u641c\u7d22\u5173\u952e\u5b57\u8fd9\u4e00\u4e2a\u53c2\u6570 \u591a\u4e2a\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e8c\u79cd\u573a\u666f\uff0c\u6211\u4eec\u9700\u8981\u53d8\u6362\u7528\u6237\u540d\u548c\u5bc6\u7801\u4e24\u4e2a\u53c2\u6570\uff0c\u5e76\u4e14\u8fd9\u4e24\u4e2a\u53c2\u6570\u9700\u8981\u5173\u8054\u7ec4\u5408 \u7136\u540e\uff0c\u5bf9\u4e8e\u53c2\u6570\u800c\u8a00\uff0c\u6211\u4eec\u53ef\u80fd\u5177\u6709\u4e00\u4e2a\u53c2\u6570\u5217\u8868\uff0c\u5728\u811a\u672c\u8fd0\u884c\u65f6\u9700\u8981\u6309\u7167\u4e0d\u540c\u7684\u89c4\u5219\u53bb\u53d6\u503c\uff0c\u4f8b\u5982\u987a\u5e8f\u53d6\u503c\u3001\u968f\u673a\u53d6\u503c\u3001\u5faa\u73af\u53d6\u503c\u7b49\u7b49\u3002 \u8fd9\u5c31\u662f\u5178\u578b\u7684\u53c2\u6570\u5316\u548c\u6570\u636e\u9a71\u52a8\u3002 \u5982\u9700\u4e86\u89e3 HttpRunner \u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u7684\u5b9e\u73b0\u539f\u7406\u548c\u6280\u672f\u7ec6\u8282\uff0c\u53ef\u524d\u5f80\u9605\u8bfb \u300aHttpRunner \u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u300b \u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u51c6\u5907 \u00b6 \u4ece 2.0.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u4e0d\u518d\u652f\u6301\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\uff1b\u53c2\u6570\u5316\u7684\u529f\u80fd\u9700\u8981\u5728 testsuite \u4e2d\u5b9e\u73b0\u3002\u53d8\u66f4\u7684\u76ee\u7684\u662f\u8ba9\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6982\u5ff5\u66f4\u7eaf\u7cb9\uff0c\u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u548c\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u6982\u5ff5\u5b9a\u4e49\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002 \u53c2\u6570\u5316\u673a\u5236\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u4e2d\u5b9e\u73b0\u3002\u5982\u9700\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a testsuite\uff0c\u5728 testsuite \u4e2d\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u5b9a\u4e49\u53c2\u6570\u5316\u914d\u7f6e\u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u7684\u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a config : name : testsuite description testcases : testcase1_name : testcase : /path/to/testcase1 testcase2_name : testcase : /path/to/testcase2 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0ctestsuite \u548c testcase \u7684\u683c\u5f0f\u5b58\u5728\u8f83\u5927\u533a\u522b\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002 \u53c2\u6570\u914d\u7f6e\u6982\u8ff0 \u00b6 \u5982\u9700\u5bf9\u67d0\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u9700\u8981\u4f7f\u7528 parameters \u5173\u952e\u5b57\uff0c\u5b9a\u4e49\u53c2\u6570\u540d\u79f0\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u53c2\u6570\u540d\u79f0\u7684\u5b9a\u4e49\u5206\u4e3a\u4e24\u79cd\u60c5\u51b5\uff1a \u72ec\u7acb\u53c2\u6570\u5355\u72ec\u8fdb\u884c\u5b9a\u4e49\uff1b \u591a\u4e2a\u53c2\u6570\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\u9700\u8981\u5c06\u5176\u5b9a\u4e49\u5728\u4e00\u8d77\uff0c\u91c7\u7528\u77ed\u6a2a\u7ebf\uff08 - \uff09\u8fdb\u884c\u8fde\u63a5\u3002 \u6570\u636e\u6e90\u6307\u5b9a\u652f\u6301\u4e09\u79cd\u65b9\u5f0f\uff1a \u5728 YAML/JSON \u4e2d\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7b80\u5355\u6613\u7528\uff0c\u9002\u5408\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5 \u901a\u8fc7\u5185\u7f6e\u7684 parameterize\uff08\u53ef\u7b80\u5199\u4e3aP\uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\uff1a\u8be5\u79cd\u65b9\u5f0f\u9700\u8981\u51c6\u5907 CSV \u6570\u636e\u6587\u4ef6\uff0c\u9002\u5408\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5 \u8c03\u7528 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7075\u6d3b\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49 Python \u51fd\u6570\u5b9e\u73b0\u4efb\u610f\u573a\u666f\u7684\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u5f53\u9700\u8981\u52a8\u6001\u751f\u6210\u53c2\u6570\u5217\u8868\u65f6\u4e5f\u9700\u8981\u9009\u62e9\u8be5\u79cd\u65b9\u5f0f \u4e09\u79cd\u65b9\u5f0f\u53ef\u6839\u636e\u5b9e\u9645\u9879\u76ee\u9700\u6c42\u8fdb\u884c\u7075\u6d3b\u9009\u62e9\uff0c\u540c\u65f6\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u7684\u7ec4\u5408\u4f7f\u7528\u3002\u5047\u5982\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u4e86\u591a\u4e2a\u53c2\u6570\uff0c\u90a3\u4e48\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u4f1a\u5bf9\u53c2\u6570\u8fdb\u884c\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u8986\u76d6\u6240\u6709\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u4f7f\u7528\u65b9\u5f0f\u6982\u89c8\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] user_id : ${P(user_id.csv)} username-password : ${get_account(10)} \u53c2\u6570\u914d\u7f6e\u8be6\u89e3 \u00b6 \u5c06\u53c2\u6570\u540d\u79f0\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u6307\u5b9a\u65b9\u5f0f\u8fdb\u884c\u7ec4\u5408\uff0c\u5171\u6709 6 \u79cd\u5f62\u5f0f\u3002\u73b0\u5206\u522b\u9488\u5bf9\u6bcf\u4e00\u7c7b\u60c5\u51b5\u8fdb\u884c\u8be6\u7ec6\u8bf4\u660e\u3002 \u72ec\u7acb\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868 \u00b6 \u5bf9\u4e8e\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5\uff0c\u6700\u7b80\u5355\u7684\u65b9\u5f0f\u662f\u76f4\u63a5\u5728 YAML/JSON \u4e2d\u6307\u5b9a\u53c2\u6570\u5217\u8868\u5185\u5bb9\u3002 \u4f8b\u5982\uff0c\u5bf9\u4e8e\u72ec\u7acb\u53c2\u6570 user_id \uff0c\u53c2\u6570\u5217\u8868\u4e3a [1001, 1002, 1003, 1004] \uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 user_id \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 [1001, 1002, 1003, 1004] \u56db\u4e2a\u503c\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u3002 \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002 \u5173\u8054\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868 \u00b6 \u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : - [ \"user1\" , \"111111\" ] - [ \"user2\" , \"222222\" ] - [ \"user3\" , \"333333\" ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 username \u548c password \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 {\"username\": \"user1\", \"password\": \"111111\"} \u3001 {\"username\": \"user2\", \"password\": \"222222\"} \u3001 {\"username\": \"user3\", \"password\": \"333333\"} \u8fd0\u884c 3 \u6b21\u6d4b\u8bd5\uff0c\u5e76\u4e14\u4fdd\u8bc1\u53c2\u6570\u503c\u603b\u662f\u6210\u5bf9\u4f7f\u7528\u3002 \u72ec\u7acb\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6 \u00b6 \u5bf9\u4e8e\u5df2\u6709\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4e14\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5\uff0c\u6bd4\u8f83\u9002\u5408\u7684\u65b9\u5f0f\u662f\u5c06\u53c2\u6570\u5217\u8868\u503c\u5b58\u50a8\u5728 CSV \u6570\u636e\u6587\u4ef6\u4e2d\u3002 \u5bf9\u4e8e CSV \u6570\u636e\u6587\u4ef6\uff0c\u9700\u8981\u9075\u5faa\u5982\u4e0b\u51e0\u9879\u7ea6\u5b9a\u7684\u89c4\u5219\uff1a CSV \u6587\u4ef6\u4e2d\u7684\u7b2c\u4e00\u884c\u5fc5\u987b\u4e3a\u53c2\u6570\u540d\u79f0\uff0c\u4ece\u7b2c\u4e8c\u884c\u5f00\u59cb\u4e3a\u53c2\u6570\u503c\uff0c\u6bcf\u4e2a\uff08\u7ec4\uff09\u503c\u5360\u4e00\u884c\uff1b \u82e5\u540c\u4e00\u4e2a CSV \u6587\u4ef6\u4e2d\u5177\u6709\u591a\u4e2a\u53c2\u6570\uff0c\u5219\u53c2\u6570\u540d\u79f0\u548c\u6570\u503c\u7684\u95f4\u9694\u7b26\u9700\u5b9e\u7528\u82f1\u6587\u9017\u53f7\uff1b \u5728 YAML/JSON \u6587\u4ef6\u5f15\u7528 CSV \u6587\u4ef6\u65f6\uff0c\u6587\u4ef6\u8def\u5f84\u4e3a\u57fa\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\uff08debugtalk.py \u6240\u5728\u8def\u5f84\uff09\u7684\u76f8\u5bf9\u8def\u5f84\u3002 \u4f8b\u5982\uff0cuser_id \u7684\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e2000\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u521b\u5efa user_id.csv\uff0c\u5e76\u4e14\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 user_id 1001 1002 ... 1999 2000 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0cuser_id.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 user_id.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${P(data/user_id.csv)} \u5373 P \u51fd\u6570\u7684\u53c2\u6570\uff08CSV \u6587\u4ef6\u8def\u5f84\uff09\u662f\u76f8\u5bf9\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684\u76f8\u5bf9\u8def\u5f84\u3002\u5f53\u7136\uff0c\u8fd9\u91cc\u4e5f\u53ef\u4ee5\u4f7f\u7528 CSV \u6587\u4ef6\u5728\u7cfb\u7edf\u4e2d\u7684\u7edd\u5bf9\u8def\u5f84\uff0c\u4e0d\u8fc7\u8fd9\u6837\u7684\u8bdd\u5728\u9879\u76ee\u8def\u5f84\u53d8\u52a8\u65f6\u5c31\u4f1a\u51fa\u73b0\u95ee\u9898\uff0c\u56e0\u6b64\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\u7684\u5f62\u5f0f\u3002 \u5173\u8054\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6 \u00b6 \u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa account.csv \uff0c\u5e76\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 username,password test1,111111 test2,222222 test3,333333 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0caccount.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 account.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${P(data/account.csv)} \u9700\u8981\u8bf4\u660e\u7684\u662f\uff0c\u5728 parameters \u4e2d\u6307\u5b9a\u7684\u53c2\u6570\u540d\u79f0\u5fc5\u987b\u4e0e CSV \u6587\u4ef6\u4e2d\u7b2c\u4e00\u884c\u7684\u53c2\u6570\u540d\u79f0\u4e00\u81f4\uff0c\u987a\u5e8f\u53ef\u4ee5\u4e0d\u4e00\u81f4\uff0c\u53c2\u6570\u4e2a\u6570\u4e5f\u53ef\u4ee5\u4e0d\u4e00\u81f4\u3002 \u4f8b\u5982\uff0c\u5728 account.csv \u6587\u4ef6\u4e2d\u53ef\u4ee5\u5305\u542b\u591a\u4e2a\u53c2\u6570\uff0cusername\u3001password\u3001phone\u3001age\uff1a username,password,phone,age test1,111111,18600000001,21 test2,222222,18600000002,22 test3,333333,18600000003,23 \u800c\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u6307\u5b9a\u53c2\u6570\u65f6\uff0c\u53ef\u4ee5\u53ea\u4f7f\u7528\u90e8\u5206\u53c2\u6570\uff0c\u5e76\u4e14\u53c2\u6570\u987a\u5e8f\u65e0\u9700\u4e0e CSV \u6587\u4ef6\u4e2d\u53c2\u6570\u540d\u79f0\u7684\u987a\u5e8f\u4e00\u81f4\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : phone-username : ${P(account.csv)} \u72ec\u7acb\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 \u00b6 \u5bf9\u4e8e\u6ca1\u6709\u73b0\u6210\u53c2\u6570\u5217\u8868\uff0c\u6216\u8005\u9700\u8981\u66f4\u7075\u6d3b\u7684\u65b9\u5f0f\u52a8\u6001\u751f\u6210\u53c2\u6570\u7684\u60c5\u51b5\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5e76\u5728 YAML/JSON \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u82e5\u9700\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e1004\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u8fd4\u56de\u53c2\u6570\u5217\u8868\u3002 def get_user_id (): return [ { \"user_id\" : 1001 }, { \"user_id\" : 1002 }, { \"user_id\" : 1003 }, { \"user_id\" : 1004 } ] \u7136\u540e\uff0c\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u6765\u6307\u5b9a\u6570\u636e\u6e90\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${get_user_id()} \u53e6\u5916\uff0c\u901a\u8fc7\u51fd\u6570\u7684\u4f20\u53c2\u673a\u5236\uff0c\u8fd8\u53ef\u4ee5\u5b9e\u73b0\u66f4\u7075\u6d3b\u7684\u53c2\u6570\u751f\u6210\u529f\u80fd\uff0c\u5728\u8c03\u7528\u51fd\u6570\u65f6\u6307\u5b9a\u9700\u8981\u751f\u6210\u7684\u53c2\u6570\u4e2a\u6570\u3002 \u5173\u8054\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 \u00b6 \u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u5b9e\u73b0\u65b9\u5f0f\u4e5f\u7c7b\u4f3c\u3002 \u4f8b\u5982\uff0c\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u51fd\u6570 get_account\uff0c\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u8d26\u53f7\u5bc6\u7801\u53c2\u6570\u5217\u8868\u3002 def get_account ( num ): accounts = [] for index in range ( 1 , num + 1 ): accounts . append ( { \"username\" : \"user %s \" % index , \"password\" : str ( index ) * 6 }, ) return accounts \u90a3\u4e48\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u53c2\u6570\u5217\u8868\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${get_account(10)} \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728\u81ea\u5b9a\u4e49\u51fd\u6570\u4e2d\uff0c\u751f\u6210\u7684\u53c2\u6570\u5217\u8868\u5fc5\u987b\u4e3a list of dict \u7684\u6570\u636e\u7ed3\u6784\uff0c\u8be5\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u4e0e CSV \u6587\u4ef6\u7684\u5904\u7406\u673a\u5236\u4fdd\u6301\u4e00\u81f4\u3002 \u53c2\u6570\u5316\u8fd0\u884c \u00b6 \u5b8c\u6210\u4ee5\u4e0a\u53c2\u6570\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u51c6\u5907\u5de5\u4f5c\u4e4b\u540e\uff0c\u53c2\u6570\u5316\u8fd0\u884c\u4e0e\u666e\u901a\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u5b8c\u5168\u4e00\u81f4\u3002 \u91c7\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff1a $ hrun tests/data/demo_parameters.yml \u91c7\u7528 locusts \u547d\u4ee4\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5\uff1a $ locusts -f tests/data/demo_parameters.yml \u533a\u522b\u5728\u4e8e\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u65f6\u904d\u5386\u4e00\u904d\u540e\u4f1a\u7ec8\u6b62\u6267\u884c\uff0c\u6027\u80fd\u6d4b\u8bd5\u65f6\u6bcf\u4e2a\u5e76\u53d1\u7528\u6237\u90fd\u4f1a\u5faa\u73af\u904d\u5386\u6240\u6709\u53c2\u6570\u3002 \u6848\u4f8b\u6f14\u793a \u00b6 \u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u83b7\u53d6 token \u7684 \u6d4b\u8bd5\u7528\u4f8b \u3002 \u70b9\u51fb\u67e5\u770b YAML \u6d4b\u8bd5\u7528\u4f8b - config : name : get token base_url : http://127.0.0.1:5000 variables : device_sn : ${gen_random_string(15)} os_platform : 'ios' app_version : '2.8.6' - test : name : get token with $device_sn, $os_platform, $app_version request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : $app_version device_sn : $device_sn os_platform : $os_platform json : sign : ${get_sign($device_sn, $os_platform, $app_version)} method : POST url : /api/get-token extract : token : content.token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528 device_sn\u3001app_version \u548c os_platform \u8fd9\u4e09\u4e2a\u53c2\u6570\u6765\u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a testsuite \uff0c\u5e76\u4e14\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\u3002 config : name : get token with parameters testcases : get token with $user_agent, $app_version, $os_platform : testcase : demo-testcase-get-token.yml parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] app_version : ${P(app_version.csv)} os_platform : ${get_os_platform()} \u5176\u4e2d\uff0c user_agent \u4f7f\u7528\u4e86\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u7684\u5f62\u5f0f\u3002 app_version \u901a\u8fc7 CSV \u6587\u4ef6\u8fdb\u884c\u53c2\u6570\u914d\u7f6e\uff0c\u5bf9\u5e94\u7684\u6587\u4ef6\u5185\u5bb9\u4e3a\uff1a app_version 2.8.5 2.8.6 os_platform \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5bf9\u5e94\u7684\u51fd\u6570\u5185\u5bb9\u4e3a\uff1a def get_os_platform (): return [ { \"os_platform\" : \"ios\" }, { \"os_platform\" : \"android\" } ] \u90a3\u4e48\uff0c\u7ecf\u8fc7\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u5e94\u8be5\u603b\u5171\u6709 3*2*2=12 \u79cd\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u70b9\u51fb\u67e5\u770b\u5b8c\u6574\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-parameters-get-token.yml INFO Start to run testcase: get token with iOS/10.1, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.66 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.026s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.76 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.012s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.49 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.39 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.04 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.44 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.14 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 7.62 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.010s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.88 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.41 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1551950193.html","title":"\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8"},{"location":"prepare/parameters/#_1","text":"\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u7ecf\u5e38\u4f1a\u9047\u5230\u5982\u4e0b\u573a\u666f\uff1a \u6d4b\u8bd5\u641c\u7d22\u529f\u80fd\uff0c\u53ea\u6709\u4e00\u4e2a\u641c\u7d22\u8f93\u5165\u6846\uff0c\u4f46\u6709 10 \u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u641c\u7d22\u5173\u952e\u5b57\uff1b \u6d4b\u8bd5\u8d26\u53f7\u767b\u5f55\u529f\u80fd\uff0c\u9700\u8981\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u6309\u7167\u7b49\u4ef7\u7c7b\u5212\u5206\u540e\u6709 20 \u79cd\u7ec4\u5408\u60c5\u51b5\u3002 \u8fd9\u91cc\u53ea\u662f\u968f\u610f\u627e\u4e86\u4e24\u4e2a\u5178\u578b\u7684\u4f8b\u5b50\uff0c\u76f8\u4fe1\u5927\u5bb6\u90fd\u6709\u9047\u5230\u8fc7\u5f88\u591a\u7c7b\u4f3c\u7684\u573a\u666f\u3002\u603b\u7ed3\u4e0b\u6765\uff0c\u5c31\u662f\u5728\u6211\u4eec\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u811a\u672c\u4e2d\u5b58\u5728\u53c2\u6570\uff0c\u5e76\u4e14\u6211\u4eec\u9700\u8981\u91c7\u7528\u4e0d\u540c\u7684\u53c2\u6570\u53bb\u8fd0\u884c\u3002 \u7ecf\u8fc7\u6982\u62ec\uff0c\u53c2\u6570\u57fa\u672c\u4e0a\u5206\u4e3a\u4e24\u79cd\u7c7b\u578b\uff1a \u5355\u4e2a\u72ec\u7acb\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e00\u79cd\u573a\u666f\uff0c\u6211\u4eec\u53ea\u9700\u8981\u53d8\u6362\u641c\u7d22\u5173\u952e\u5b57\u8fd9\u4e00\u4e2a\u53c2\u6570 \u591a\u4e2a\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e8c\u79cd\u573a\u666f\uff0c\u6211\u4eec\u9700\u8981\u53d8\u6362\u7528\u6237\u540d\u548c\u5bc6\u7801\u4e24\u4e2a\u53c2\u6570\uff0c\u5e76\u4e14\u8fd9\u4e24\u4e2a\u53c2\u6570\u9700\u8981\u5173\u8054\u7ec4\u5408 \u7136\u540e\uff0c\u5bf9\u4e8e\u53c2\u6570\u800c\u8a00\uff0c\u6211\u4eec\u53ef\u80fd\u5177\u6709\u4e00\u4e2a\u53c2\u6570\u5217\u8868\uff0c\u5728\u811a\u672c\u8fd0\u884c\u65f6\u9700\u8981\u6309\u7167\u4e0d\u540c\u7684\u89c4\u5219\u53bb\u53d6\u503c\uff0c\u4f8b\u5982\u987a\u5e8f\u53d6\u503c\u3001\u968f\u673a\u53d6\u503c\u3001\u5faa\u73af\u53d6\u503c\u7b49\u7b49\u3002 \u8fd9\u5c31\u662f\u5178\u578b\u7684\u53c2\u6570\u5316\u548c\u6570\u636e\u9a71\u52a8\u3002 \u5982\u9700\u4e86\u89e3 HttpRunner \u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u7684\u5b9e\u73b0\u539f\u7406\u548c\u6280\u672f\u7ec6\u8282\uff0c\u53ef\u524d\u5f80\u9605\u8bfb \u300aHttpRunner \u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u300b \u3002","title":"\u4ecb\u7ecd"},{"location":"prepare/parameters/#testsuite","text":"\u4ece 2.0.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u4e0d\u518d\u652f\u6301\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\uff1b\u53c2\u6570\u5316\u7684\u529f\u80fd\u9700\u8981\u5728 testsuite \u4e2d\u5b9e\u73b0\u3002\u53d8\u66f4\u7684\u76ee\u7684\u662f\u8ba9\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6982\u5ff5\u66f4\u7eaf\u7cb9\uff0c\u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u548c\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u6982\u5ff5\u5b9a\u4e49\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002 \u53c2\u6570\u5316\u673a\u5236\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u4e2d\u5b9e\u73b0\u3002\u5982\u9700\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a testsuite\uff0c\u5728 testsuite \u4e2d\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u5b9a\u4e49\u53c2\u6570\u5316\u914d\u7f6e\u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u7684\u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a config : name : testsuite description testcases : testcase1_name : testcase : /path/to/testcase1 testcase2_name : testcase : /path/to/testcase2 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0ctestsuite \u548c testcase \u7684\u683c\u5f0f\u5b58\u5728\u8f83\u5927\u533a\u522b\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u51c6\u5907"},{"location":"prepare/parameters/#_2","text":"\u5982\u9700\u5bf9\u67d0\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u9700\u8981\u4f7f\u7528 parameters \u5173\u952e\u5b57\uff0c\u5b9a\u4e49\u53c2\u6570\u540d\u79f0\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u53c2\u6570\u540d\u79f0\u7684\u5b9a\u4e49\u5206\u4e3a\u4e24\u79cd\u60c5\u51b5\uff1a \u72ec\u7acb\u53c2\u6570\u5355\u72ec\u8fdb\u884c\u5b9a\u4e49\uff1b \u591a\u4e2a\u53c2\u6570\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\u9700\u8981\u5c06\u5176\u5b9a\u4e49\u5728\u4e00\u8d77\uff0c\u91c7\u7528\u77ed\u6a2a\u7ebf\uff08 - \uff09\u8fdb\u884c\u8fde\u63a5\u3002 \u6570\u636e\u6e90\u6307\u5b9a\u652f\u6301\u4e09\u79cd\u65b9\u5f0f\uff1a \u5728 YAML/JSON \u4e2d\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7b80\u5355\u6613\u7528\uff0c\u9002\u5408\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5 \u901a\u8fc7\u5185\u7f6e\u7684 parameterize\uff08\u53ef\u7b80\u5199\u4e3aP\uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\uff1a\u8be5\u79cd\u65b9\u5f0f\u9700\u8981\u51c6\u5907 CSV \u6570\u636e\u6587\u4ef6\uff0c\u9002\u5408\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5 \u8c03\u7528 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7075\u6d3b\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49 Python \u51fd\u6570\u5b9e\u73b0\u4efb\u610f\u573a\u666f\u7684\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u5f53\u9700\u8981\u52a8\u6001\u751f\u6210\u53c2\u6570\u5217\u8868\u65f6\u4e5f\u9700\u8981\u9009\u62e9\u8be5\u79cd\u65b9\u5f0f \u4e09\u79cd\u65b9\u5f0f\u53ef\u6839\u636e\u5b9e\u9645\u9879\u76ee\u9700\u6c42\u8fdb\u884c\u7075\u6d3b\u9009\u62e9\uff0c\u540c\u65f6\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u7684\u7ec4\u5408\u4f7f\u7528\u3002\u5047\u5982\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u4e86\u591a\u4e2a\u53c2\u6570\uff0c\u90a3\u4e48\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u4f1a\u5bf9\u53c2\u6570\u8fdb\u884c\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u8986\u76d6\u6240\u6709\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u4f7f\u7528\u65b9\u5f0f\u6982\u89c8\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] user_id : ${P(user_id.csv)} username-password : ${get_account(10)}","title":"\u53c2\u6570\u914d\u7f6e\u6982\u8ff0"},{"location":"prepare/parameters/#_3","text":"\u5c06\u53c2\u6570\u540d\u79f0\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u6307\u5b9a\u65b9\u5f0f\u8fdb\u884c\u7ec4\u5408\uff0c\u5171\u6709 6 \u79cd\u5f62\u5f0f\u3002\u73b0\u5206\u522b\u9488\u5bf9\u6bcf\u4e00\u7c7b\u60c5\u51b5\u8fdb\u884c\u8be6\u7ec6\u8bf4\u660e\u3002","title":"\u53c2\u6570\u914d\u7f6e\u8be6\u89e3"},{"location":"prepare/parameters/#_4","text":"\u5bf9\u4e8e\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5\uff0c\u6700\u7b80\u5355\u7684\u65b9\u5f0f\u662f\u76f4\u63a5\u5728 YAML/JSON \u4e2d\u6307\u5b9a\u53c2\u6570\u5217\u8868\u5185\u5bb9\u3002 \u4f8b\u5982\uff0c\u5bf9\u4e8e\u72ec\u7acb\u53c2\u6570 user_id \uff0c\u53c2\u6570\u5217\u8868\u4e3a [1001, 1002, 1003, 1004] \uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 user_id \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 [1001, 1002, 1003, 1004] \u56db\u4e2a\u503c\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u3002 \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002","title":"\u72ec\u7acb\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868"},{"location":"prepare/parameters/#_5","text":"\u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : - [ \"user1\" , \"111111\" ] - [ \"user2\" , \"222222\" ] - [ \"user3\" , \"333333\" ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 username \u548c password \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 {\"username\": \"user1\", \"password\": \"111111\"} \u3001 {\"username\": \"user2\", \"password\": \"222222\"} \u3001 {\"username\": \"user3\", \"password\": \"333333\"} \u8fd0\u884c 3 \u6b21\u6d4b\u8bd5\uff0c\u5e76\u4e14\u4fdd\u8bc1\u53c2\u6570\u503c\u603b\u662f\u6210\u5bf9\u4f7f\u7528\u3002","title":"\u5173\u8054\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868"},{"location":"prepare/parameters/#csv","text":"\u5bf9\u4e8e\u5df2\u6709\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4e14\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5\uff0c\u6bd4\u8f83\u9002\u5408\u7684\u65b9\u5f0f\u662f\u5c06\u53c2\u6570\u5217\u8868\u503c\u5b58\u50a8\u5728 CSV \u6570\u636e\u6587\u4ef6\u4e2d\u3002 \u5bf9\u4e8e CSV \u6570\u636e\u6587\u4ef6\uff0c\u9700\u8981\u9075\u5faa\u5982\u4e0b\u51e0\u9879\u7ea6\u5b9a\u7684\u89c4\u5219\uff1a CSV \u6587\u4ef6\u4e2d\u7684\u7b2c\u4e00\u884c\u5fc5\u987b\u4e3a\u53c2\u6570\u540d\u79f0\uff0c\u4ece\u7b2c\u4e8c\u884c\u5f00\u59cb\u4e3a\u53c2\u6570\u503c\uff0c\u6bcf\u4e2a\uff08\u7ec4\uff09\u503c\u5360\u4e00\u884c\uff1b \u82e5\u540c\u4e00\u4e2a CSV \u6587\u4ef6\u4e2d\u5177\u6709\u591a\u4e2a\u53c2\u6570\uff0c\u5219\u53c2\u6570\u540d\u79f0\u548c\u6570\u503c\u7684\u95f4\u9694\u7b26\u9700\u5b9e\u7528\u82f1\u6587\u9017\u53f7\uff1b \u5728 YAML/JSON \u6587\u4ef6\u5f15\u7528 CSV \u6587\u4ef6\u65f6\uff0c\u6587\u4ef6\u8def\u5f84\u4e3a\u57fa\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\uff08debugtalk.py \u6240\u5728\u8def\u5f84\uff09\u7684\u76f8\u5bf9\u8def\u5f84\u3002 \u4f8b\u5982\uff0cuser_id \u7684\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e2000\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u521b\u5efa user_id.csv\uff0c\u5e76\u4e14\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 user_id 1001 1002 ... 1999 2000 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0cuser_id.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 user_id.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${P(data/user_id.csv)} \u5373 P \u51fd\u6570\u7684\u53c2\u6570\uff08CSV \u6587\u4ef6\u8def\u5f84\uff09\u662f\u76f8\u5bf9\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684\u76f8\u5bf9\u8def\u5f84\u3002\u5f53\u7136\uff0c\u8fd9\u91cc\u4e5f\u53ef\u4ee5\u4f7f\u7528 CSV \u6587\u4ef6\u5728\u7cfb\u7edf\u4e2d\u7684\u7edd\u5bf9\u8def\u5f84\uff0c\u4e0d\u8fc7\u8fd9\u6837\u7684\u8bdd\u5728\u9879\u76ee\u8def\u5f84\u53d8\u52a8\u65f6\u5c31\u4f1a\u51fa\u73b0\u95ee\u9898\uff0c\u56e0\u6b64\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\u7684\u5f62\u5f0f\u3002","title":"\u72ec\u7acb\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6"},{"location":"prepare/parameters/#csv_1","text":"\u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa account.csv \uff0c\u5e76\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 username,password test1,111111 test2,222222 test3,333333 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0caccount.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 account.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${P(data/account.csv)} \u9700\u8981\u8bf4\u660e\u7684\u662f\uff0c\u5728 parameters \u4e2d\u6307\u5b9a\u7684\u53c2\u6570\u540d\u79f0\u5fc5\u987b\u4e0e CSV \u6587\u4ef6\u4e2d\u7b2c\u4e00\u884c\u7684\u53c2\u6570\u540d\u79f0\u4e00\u81f4\uff0c\u987a\u5e8f\u53ef\u4ee5\u4e0d\u4e00\u81f4\uff0c\u53c2\u6570\u4e2a\u6570\u4e5f\u53ef\u4ee5\u4e0d\u4e00\u81f4\u3002 \u4f8b\u5982\uff0c\u5728 account.csv \u6587\u4ef6\u4e2d\u53ef\u4ee5\u5305\u542b\u591a\u4e2a\u53c2\u6570\uff0cusername\u3001password\u3001phone\u3001age\uff1a username,password,phone,age test1,111111,18600000001,21 test2,222222,18600000002,22 test3,333333,18600000003,23 \u800c\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u6307\u5b9a\u53c2\u6570\u65f6\uff0c\u53ef\u4ee5\u53ea\u4f7f\u7528\u90e8\u5206\u53c2\u6570\uff0c\u5e76\u4e14\u53c2\u6570\u987a\u5e8f\u65e0\u9700\u4e0e CSV \u6587\u4ef6\u4e2d\u53c2\u6570\u540d\u79f0\u7684\u987a\u5e8f\u4e00\u81f4\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : phone-username : ${P(account.csv)}","title":"\u5173\u8054\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6"},{"location":"prepare/parameters/#_6","text":"\u5bf9\u4e8e\u6ca1\u6709\u73b0\u6210\u53c2\u6570\u5217\u8868\uff0c\u6216\u8005\u9700\u8981\u66f4\u7075\u6d3b\u7684\u65b9\u5f0f\u52a8\u6001\u751f\u6210\u53c2\u6570\u7684\u60c5\u51b5\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5e76\u5728 YAML/JSON \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u82e5\u9700\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e1004\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u8fd4\u56de\u53c2\u6570\u5217\u8868\u3002 def get_user_id (): return [ { \"user_id\" : 1001 }, { \"user_id\" : 1002 }, { \"user_id\" : 1003 }, { \"user_id\" : 1004 } ] \u7136\u540e\uff0c\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u6765\u6307\u5b9a\u6570\u636e\u6e90\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${get_user_id()} \u53e6\u5916\uff0c\u901a\u8fc7\u51fd\u6570\u7684\u4f20\u53c2\u673a\u5236\uff0c\u8fd8\u53ef\u4ee5\u5b9e\u73b0\u66f4\u7075\u6d3b\u7684\u53c2\u6570\u751f\u6210\u529f\u80fd\uff0c\u5728\u8c03\u7528\u51fd\u6570\u65f6\u6307\u5b9a\u9700\u8981\u751f\u6210\u7684\u53c2\u6570\u4e2a\u6570\u3002","title":"\u72ec\u7acb\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570"},{"location":"prepare/parameters/#_7","text":"\u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u5b9e\u73b0\u65b9\u5f0f\u4e5f\u7c7b\u4f3c\u3002 \u4f8b\u5982\uff0c\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u51fd\u6570 get_account\uff0c\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u8d26\u53f7\u5bc6\u7801\u53c2\u6570\u5217\u8868\u3002 def get_account ( num ): accounts = [] for index in range ( 1 , num + 1 ): accounts . append ( { \"username\" : \"user %s \" % index , \"password\" : str ( index ) * 6 }, ) return accounts \u90a3\u4e48\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u53c2\u6570\u5217\u8868\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${get_account(10)} \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728\u81ea\u5b9a\u4e49\u51fd\u6570\u4e2d\uff0c\u751f\u6210\u7684\u53c2\u6570\u5217\u8868\u5fc5\u987b\u4e3a list of dict \u7684\u6570\u636e\u7ed3\u6784\uff0c\u8be5\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u4e0e CSV \u6587\u4ef6\u7684\u5904\u7406\u673a\u5236\u4fdd\u6301\u4e00\u81f4\u3002","title":"\u5173\u8054\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570"},{"location":"prepare/parameters/#_8","text":"\u5b8c\u6210\u4ee5\u4e0a\u53c2\u6570\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u51c6\u5907\u5de5\u4f5c\u4e4b\u540e\uff0c\u53c2\u6570\u5316\u8fd0\u884c\u4e0e\u666e\u901a\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u5b8c\u5168\u4e00\u81f4\u3002 \u91c7\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff1a $ hrun tests/data/demo_parameters.yml \u91c7\u7528 locusts \u547d\u4ee4\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5\uff1a $ locusts -f tests/data/demo_parameters.yml \u533a\u522b\u5728\u4e8e\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u65f6\u904d\u5386\u4e00\u904d\u540e\u4f1a\u7ec8\u6b62\u6267\u884c\uff0c\u6027\u80fd\u6d4b\u8bd5\u65f6\u6bcf\u4e2a\u5e76\u53d1\u7528\u6237\u90fd\u4f1a\u5faa\u73af\u904d\u5386\u6240\u6709\u53c2\u6570\u3002","title":"\u53c2\u6570\u5316\u8fd0\u884c"},{"location":"prepare/parameters/#_9","text":"\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u83b7\u53d6 token \u7684 \u6d4b\u8bd5\u7528\u4f8b \u3002 \u70b9\u51fb\u67e5\u770b YAML \u6d4b\u8bd5\u7528\u4f8b - config : name : get token base_url : http://127.0.0.1:5000 variables : device_sn : ${gen_random_string(15)} os_platform : 'ios' app_version : '2.8.6' - test : name : get token with $device_sn, $os_platform, $app_version request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : $app_version device_sn : $device_sn os_platform : $os_platform json : sign : ${get_sign($device_sn, $os_platform, $app_version)} method : POST url : /api/get-token extract : token : content.token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528 device_sn\u3001app_version \u548c os_platform \u8fd9\u4e09\u4e2a\u53c2\u6570\u6765\u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a testsuite \uff0c\u5e76\u4e14\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\u3002 config : name : get token with parameters testcases : get token with $user_agent, $app_version, $os_platform : testcase : demo-testcase-get-token.yml parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] app_version : ${P(app_version.csv)} os_platform : ${get_os_platform()} \u5176\u4e2d\uff0c user_agent \u4f7f\u7528\u4e86\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u7684\u5f62\u5f0f\u3002 app_version \u901a\u8fc7 CSV \u6587\u4ef6\u8fdb\u884c\u53c2\u6570\u914d\u7f6e\uff0c\u5bf9\u5e94\u7684\u6587\u4ef6\u5185\u5bb9\u4e3a\uff1a app_version 2.8.5 2.8.6 os_platform \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5bf9\u5e94\u7684\u51fd\u6570\u5185\u5bb9\u4e3a\uff1a def get_os_platform (): return [ { \"os_platform\" : \"ios\" }, { \"os_platform\" : \"android\" } ] \u90a3\u4e48\uff0c\u7ecf\u8fc7\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u5e94\u8be5\u603b\u5171\u6709 3*2*2=12 \u79cd\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u70b9\u51fb\u67e5\u770b\u5b8c\u6574\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-parameters-get-token.yml INFO Start to run testcase: get token with iOS/10.1, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.66 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.026s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.76 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.012s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.49 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.39 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.04 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.44 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.14 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 7.62 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.010s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.88 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.41 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1551950193.html","title":"\u6848\u4f8b\u6f14\u793a"},{"location":"prepare/project-structure/","text":"\u6587\u4ef6\u7c7b\u578b\b\u8bf4\u660e \u00b6 \u5728 HttpRunner \u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u4e2d\uff0c\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u51e0\u7c7b\u6587\u4ef6\uff1a YAML/JSON \uff08\u5fc5\u987b\uff09\uff1a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff0c\u5b58\u50a8\u63a5\u53e3\u6d4b\u8bd5\u76f8\u5173\u4fe1\u606f debugtalk.py \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u4e2d\u903b\u8f91\u8fd0\u7b97\u8f85\u52a9\u51fd\u6570 \u8be5\u6587\u4ef6\u5b58\u5728\u65f6\uff0c\u5c06\u4f5c\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\u5b9a\u4f4d\u6807\u8bb0\uff0c\u5176\u6240\u5728\u76ee\u5f55\u5373\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8be5\u6587\u4ef6\u4e0d\u5b58\u5728\u65f6\uff0c\u8fd0\u884c\u6d4b\u8bd5\u7684\u6240\u5728\u8def\u5f84\uff08 CWD \uff09\u5c06\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u7684\u76f8\u5bf9\u8def\u5f84\uff08\u4f8b\u5982 .csv \uff09\u5747\u9700\u57fa\u4e8e\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8fd0\u884c\u6d4b\u8bd5\u540e\uff0c\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u5939\uff08 reports \uff09\u4f1a\u751f\u6210\u5728\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 .env \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u73af\u5883\u53d8\u91cf\uff0c\u901a\u5e38\u7528\u4e8e\u5b58\u50a8\u9879\u76ee\u654f\u611f\u4fe1\u606f .csv \uff08\u53ef\u9009\uff09\uff1a\u9879\u76ee\u6570\u636e\u6587\u4ef6\uff0c\u7528\u4e8e\u8fdb\u884c\u6570\u636e\u9a71\u52a8 reports \uff1a\u9ed8\u8ba4\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u7684\u5b58\u50a8\u6587\u4ef6\u5939 \u9879\u76ee\u6587\u4ef6\u7ed3\u6784 \u00b6 \u5bf9\u4e8e\u63a5\u53e3\u6570\u6bd4\u8f83\u5c11\uff0c\u6216\u8005\u6d4b\u8bd5\u573a\u666f\u6bd4\u8f83\u7b80\u5355\u7684\u9879\u76ee\uff0c\u7ec4\u7ec7\u6d4b\u8bd5\u7528\u4f8b\u65f6\u65e0\u9700\u5206\u5c42\u3002\u5728\u6b64\u79cd\u60c5\u51b5\u4e0b\uff0c\u9879\u76ee\u6587\u4ef6\u7684\u76ee\u5f55\u7ed3\u6784\u6ca1\u6709\u4efb\u4f55\u8981\u6c42\uff0c\u5728\u9879\u76ee\u4e2d\u53ea\u9700\u8981\b\u4e00\u5806 YAML/JSON \u6587\u4ef6\u5373\u53ef\uff0c\u6bcf\u4e00\u4e2a\u6587\u4ef6\u5355\u72ec\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff1b\u6839\u636e\u9700\u8981\uff0c\u9879\u76ee\u4e2d\u53ef\u80fd\u8fd8\u4f1a\u6709 debugtalk.py \u3001 .env \u7b49\u6587\u4ef6\u3002 \u63a8\u8350\u7684\u9879\u76ee\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u793a\u4f8b\u5982\u4e0b\uff1a $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 reports \u251c\u2500\u2500 testcase1.yml \u2514\u2500\u2500 testcase2.json","title":"\u9879\u76ee\u6587\u4ef6\u7ec4\u7ec7"},{"location":"prepare/project-structure/#_1","text":"\u5728 HttpRunner \u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u4e2d\uff0c\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u51e0\u7c7b\u6587\u4ef6\uff1a YAML/JSON \uff08\u5fc5\u987b\uff09\uff1a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff0c\u5b58\u50a8\u63a5\u53e3\u6d4b\u8bd5\u76f8\u5173\u4fe1\u606f debugtalk.py \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u4e2d\u903b\u8f91\u8fd0\u7b97\u8f85\u52a9\u51fd\u6570 \u8be5\u6587\u4ef6\u5b58\u5728\u65f6\uff0c\u5c06\u4f5c\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\u5b9a\u4f4d\u6807\u8bb0\uff0c\u5176\u6240\u5728\u76ee\u5f55\u5373\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8be5\u6587\u4ef6\u4e0d\u5b58\u5728\u65f6\uff0c\u8fd0\u884c\u6d4b\u8bd5\u7684\u6240\u5728\u8def\u5f84\uff08 CWD \uff09\u5c06\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u7684\u76f8\u5bf9\u8def\u5f84\uff08\u4f8b\u5982 .csv \uff09\u5747\u9700\u57fa\u4e8e\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8fd0\u884c\u6d4b\u8bd5\u540e\uff0c\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u5939\uff08 reports \uff09\u4f1a\u751f\u6210\u5728\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 .env \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u73af\u5883\u53d8\u91cf\uff0c\u901a\u5e38\u7528\u4e8e\u5b58\u50a8\u9879\u76ee\u654f\u611f\u4fe1\u606f .csv \uff08\u53ef\u9009\uff09\uff1a\u9879\u76ee\u6570\u636e\u6587\u4ef6\uff0c\u7528\u4e8e\u8fdb\u884c\u6570\u636e\u9a71\u52a8 reports \uff1a\u9ed8\u8ba4\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u7684\u5b58\u50a8\u6587\u4ef6\u5939","title":"\u6587\u4ef6\u7c7b\u578b\b\u8bf4\u660e"},{"location":"prepare/project-structure/#_2","text":"\u5bf9\u4e8e\u63a5\u53e3\u6570\u6bd4\u8f83\u5c11\uff0c\u6216\u8005\u6d4b\u8bd5\u573a\u666f\u6bd4\u8f83\u7b80\u5355\u7684\u9879\u76ee\uff0c\u7ec4\u7ec7\u6d4b\u8bd5\u7528\u4f8b\u65f6\u65e0\u9700\u5206\u5c42\u3002\u5728\u6b64\u79cd\u60c5\u51b5\u4e0b\uff0c\u9879\u76ee\u6587\u4ef6\u7684\u76ee\u5f55\u7ed3\u6784\u6ca1\u6709\u4efb\u4f55\u8981\u6c42\uff0c\u5728\u9879\u76ee\u4e2d\u53ea\u9700\u8981\b\u4e00\u5806 YAML/JSON \u6587\u4ef6\u5373\u53ef\uff0c\u6bcf\u4e00\u4e2a\u6587\u4ef6\u5355\u72ec\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff1b\u6839\u636e\u9700\u8981\uff0c\u9879\u76ee\u4e2d\u53ef\u80fd\u8fd8\u4f1a\u6709 debugtalk.py \u3001 .env \u7b49\u6587\u4ef6\u3002 \u63a8\u8350\u7684\u9879\u76ee\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u793a\u4f8b\u5982\u4e0b\uff1a $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 reports \u251c\u2500\u2500 testcase1.yml \u2514\u2500\u2500 testcase2.json","title":"\u9879\u76ee\u6587\u4ef6\u7ed3\u6784"},{"location":"prepare/record/","text":"\u4e3a\u4e86\u7b80\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7f16\u5199\u5de5\u4f5c\uff0cHttpRunner \u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u7684\u529f\u80fd\uff0c\u5bf9\u5e94\u7684\u8f6c\u6362\u5de5\u5177\u4e3a\u4e00\u4e2a\u72ec\u7acb\u7684\u9879\u76ee\uff1a har2case \u3002 \u7b80\u5355\u6765\u8bf4\uff0c\u5c31\u662f\u5f53\u524d\u4e3b\u6d41\u7684\u6293\u5305\u5de5\u5177\u548c\u6d4f\u89c8\u5668\u90fd\u652f\u6301\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a\u6807\u51c6\u901a\u7528\u7684 HAR \u683c\u5f0f\uff08HTTP Archive\uff09\uff0c\u7136\u540e HttpRunner \u5b9e\u73b0\u4e86\u5c06 HAR \u683c\u5f0f\u7684\u6570\u636e\u5305\u8f6c\u6362\u4e3a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u529f\u80fd\u3002 \u83b7\u53d6 HAR \u6570\u636e\u5305 \u00b6 \u5728\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\u3002\u5728 Charles Proxy \u4e2d\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff0c\u9009\u4e2d\u9700\u8981\u8f6c\u6362\u7684\u63a5\u53e3\uff08\u53ef\u591a\u9009\u6216\u5168\u9009\uff09\uff0c\u70b9\u51fb\u53f3\u952e\uff0c\u5728\u60ac\u6d6e\u7684\u83dc\u5355\u76ee\u5f55\u4e2d\u70b9\u51fb\u3010Export...\u3011\uff0c\u683c\u5f0f\u9009\u62e9 HTTP Archive(.har) \u540e\u4fdd\u5b58\u5373\u53ef\uff1b\u5047\u8bbe\u6211\u4eec\u4fdd\u5b58\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo.har\u3002 \u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c har2case \u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har INFO:root:Start to generate testcase. INFO:root:dump testcase to JSON format. INFO:root:Generate JSON testcase successfully: docs/data/demo-quickstart.json \u52a0\u4e0a -2y / --to-yml \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002","title":"\u5f55\u5236\u751f\u6210\u7528\u4f8b"},{"location":"prepare/record/#har","text":"\u5728\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\u3002\u5728 Charles Proxy \u4e2d\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff0c\u9009\u4e2d\u9700\u8981\u8f6c\u6362\u7684\u63a5\u53e3\uff08\u53ef\u591a\u9009\u6216\u5168\u9009\uff09\uff0c\u70b9\u51fb\u53f3\u952e\uff0c\u5728\u60ac\u6d6e\u7684\u83dc\u5355\u76ee\u5f55\u4e2d\u70b9\u51fb\u3010Export...\u3011\uff0c\u683c\u5f0f\u9009\u62e9 HTTP Archive(.har) \u540e\u4fdd\u5b58\u5373\u53ef\uff1b\u5047\u8bbe\u6211\u4eec\u4fdd\u5b58\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo.har\u3002","title":"\u83b7\u53d6 HAR \u6570\u636e\u5305"},{"location":"prepare/record/#_1","text":"\u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c har2case \u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har INFO:root:Start to generate testcase. INFO:root:dump testcase to JSON format. INFO:root:Generate JSON testcase successfully: docs/data/demo-quickstart.json \u52a0\u4e0a -2y / --to-yml \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002","title":"\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b"},{"location":"prepare/request-hook/","text":"\u6982\u8ff0 \u00b6 HttpRunner \u4ece 1.4.5 \u7248\u672c\u5f00\u59cb\u5b9e\u73b0\u4e86\u5168\u65b0\u7684 hook \u673a\u5236\uff0c\u53ef\u4ee5\u5728\u8bf7\u6c42\u524d\u548c\u8bf7\u6c42\u540e\u8c03\u7528\u94a9\u5b50\u51fd\u6570\u3002 \u8c03\u7528 hook \u51fd\u6570 \u00b6 hook \u673a\u5236\u5206\u4e3a\u4e24\u4e2a\u5c42\u7ea7\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09 \u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09 \u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09 \u00b6 \u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u7684 config \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u5f00\u59cb\u6267\u884c\u524d\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\u3002 teardown_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u7ed3\u675f\u6267\u884c\u540e\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\u3002 - config : name : basic test with httpbin request : base_url : http://127.0.0.1:3458/ setup_hooks : - ${hook_print(setup)} teardown_hooks : - ${hook_print(teardown)} \u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09 \u00b6 \u5728 YAML/JSON \u6d4b\u8bd5\u6b65\u9aa4\u7684 test \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u8bf7\u6c42\u7684 request \u5185\u5bb9\u8fdb\u884c\u9884\u5904\u7406\u3002 teardown_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u54cd\u5e94\u7684 response \u8fdb\u884c\u4fee\u6539\uff0c\u4f8b\u5982\u8fdb\u884c\u52a0\u89e3\u5bc6\u7b49\u5904\u7406\u3002 \"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]} ], \"setup_hooks\" : [ \"${setup_hook_prepare_kwargs($request)}\" , \"${setup_hook_httpntlmauth($request)}\" ], \"teardown_hooks\" : [ \"${teardown_hook_sleep_N_secs($response, 2)}\" ] } \u7f16\u5199 hook \u51fd\u6570 \u00b6 hook \u51fd\u6570\u7684\u5b9a\u4e49\u653e\u7f6e\u5728\u9879\u76ee\u7684 debugtalk.py \u4e2d\uff0c\u5728 YAML/JSON \u4e2d\u8c03\u7528 hook \u51fd\u6570\u4ecd\u7136\u662f\u91c7\u7528 ${func($a, $b)} \u7684\u5f62\u5f0f\u3002 \u5bf9\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u4e0e YAML/JSON \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u5b8c\u5168\u76f8\u540c\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49\u53c2\u6570\u4f20\u53c2\u7684\u5f62\u5f0f\u6765\u5b9e\u73b0\u7075\u6d3b\u5e94\u7528\u3002 def hook_print ( msg ): print ( msg ) \u5bf9\u4e8e\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165\u4e0e\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u76f8\u5173\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 $request \u548c\u54cd\u5e94\u7684 $response \uff0c\u7528\u4e8e\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u7075\u6d3b\u5e94\u7528\u3002 setup_hooks \u00b6 \u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 setup_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $request \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 request \u7684\u5168\u90e8\u5185\u5bb9\u3002\u56e0\u4e3a request \u662f\u53ef\u53d8\u53c2\u6570\u7c7b\u578b\uff08dict\uff09\uff0c\u56e0\u6b64\u8be5\u51fd\u6570\u53c2\u6570\u4e3a\u5f15\u7528\u4f20\u9012\uff0c\u5f53\u6211\u4eec\u9700\u8981\u5bf9\u8bf7\u6c42\u53c2\u6570\u8fdb\u884c\u9884\u5904\u7406\u65f6\u5c24\u5176\u6709\u7528\u3002 e.g. def setup_hook_prepare_kwargs ( request ): if request [ \"method\" ] == \"POST\" : content_type = request . get ( \"headers\" , {}) . get ( \"content-type\" ) if content_type and \"data\" in request : # if request content-type is application/json, request data should be dumped if content_type . startswith ( \"application/json\" ) and isinstance ( request [ \"data\" ], ( dict , list )): request [ \"data\" ] = json . dumps ( request [ \"data\" ]) if isinstance ( request [ \"data\" ], str ): request [ \"data\" ] = request [ \"data\" ] . encode ( 'utf-8' ) def setup_hook_httpntlmauth ( request ): if \"httpntlmauth\" in request : from requests_ntlm import HttpNtlmAuth auth_account = request . pop ( \"httpntlmauth\" ) request [ \"auth\" ] = HttpNtlmAuth ( auth_account [ \"username\" ], auth_account [ \"password\" ]) \u901a\u8fc7\u4e0a\u8ff0\u7684 setup_hook_prepare_kwargs \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0\u6839\u636e\u8bf7\u6c42\u65b9\u6cd5\u548c\u8bf7\u6c42\u7684 Content-Type \u6765\u5bf9\u8bf7\u6c42\u7684 data \u8fdb\u884c\u52a0\u5de5\u5904\u7406\uff1b\u901a\u8fc7 setup_hook_httpntlmauth \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0 HttpNtlmAuth \u6743\u9650\u6388\u6743\u3002 teardown_hooks \u00b6 \u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 teardown_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $response \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u8bf7\u6c42\u7684\u54cd\u5e94\u5b9e\u4f8b\uff08requests.Response\uff09\u3002 e.g. def teardown_hook_sleep_N_secs ( response , n_secs ): \"\"\" sleep n seconds after request \"\"\" if response . status_code == 200 : time . sleep ( 0.1 ) else : time . sleep ( n_secs ) \u901a\u8fc7\u4e0a\u8ff0\u7684 teardown_hook_sleep_N_secs \u51fd\u6570\uff0c\u53ef\u4ee5\u6839\u636e\u63a5\u53e3\u54cd\u5e94\u7684\u72b6\u6001\u7801\u6765\u8fdb\u884c\u4e0d\u540c\u65f6\u95f4\u7684\u5ef6\u8fdf\u7b49\u5f85\u3002 \u53e6\u5916\uff0c\u5728 teardown_hooks \u51fd\u6570\u4e2d\u8fd8\u53ef\u4ee5\u5bf9 response \u8fdb\u884c\u4fee\u6539\u3002\u5f53\u6211\u4eec\u9700\u8981\u5148\u5bf9\u54cd\u5e94\u5185\u5bb9\u8fdb\u884c\u5904\u7406\uff08\u4f8b\u5982\u52a0\u89e3\u5bc6\u3001\u53c2\u6570\u8fd0\u7b97\uff09\uff0c\u518d\u8fdb\u884c\u53c2\u6570\u63d0\u53d6\uff08extract\uff09\u548c\u6821\u9a8c\uff08validate\uff09\u65f6\u5c24\u5176\u6709\u7528\u3002 \u4f8b\u5982\u5728\u4e0b\u9762\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u5728\u6267\u884c\u6d4b\u8bd5\u540e\uff0c\u901a\u8fc7 teardown_hooks \u51fd\u6570\u5c06\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u548c headers \u8fdb\u884c\u4e86\u4fee\u6539\uff0c\u7136\u540e\u518d\u8fdb\u884c\u4e86\u6821\u9a8c\u3002 - test : name : alter response request : url : /headers method : GET teardown_hooks : - ${alter_response($response)} validate : - eq : [ \"status_code\" , 500 ] - eq : [ \"headers.content-type\" , \"html/text\" ] def alter_response ( response ): response . status_code = 500 response . headers [ \"Content-Type\" ] = \"html/text\"","title":"hook\u673a\u5236"},{"location":"prepare/request-hook/#_1","text":"HttpRunner \u4ece 1.4.5 \u7248\u672c\u5f00\u59cb\u5b9e\u73b0\u4e86\u5168\u65b0\u7684 hook \u673a\u5236\uff0c\u53ef\u4ee5\u5728\u8bf7\u6c42\u524d\u548c\u8bf7\u6c42\u540e\u8c03\u7528\u94a9\u5b50\u51fd\u6570\u3002","title":"\u6982\u8ff0"},{"location":"prepare/request-hook/#hook","text":"hook \u673a\u5236\u5206\u4e3a\u4e24\u4e2a\u5c42\u7ea7\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09 \u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09","title":"\u8c03\u7528 hook \u51fd\u6570"},{"location":"prepare/request-hook/#testcase","text":"\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u7684 config \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u5f00\u59cb\u6267\u884c\u524d\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\u3002 teardown_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u7ed3\u675f\u6267\u884c\u540e\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\u3002 - config : name : basic test with httpbin request : base_url : http://127.0.0.1:3458/ setup_hooks : - ${hook_print(setup)} teardown_hooks : - ${hook_print(teardown)}","title":"\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09"},{"location":"prepare/request-hook/#teststep","text":"\u5728 YAML/JSON \u6d4b\u8bd5\u6b65\u9aa4\u7684 test \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u8bf7\u6c42\u7684 request \u5185\u5bb9\u8fdb\u884c\u9884\u5904\u7406\u3002 teardown_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u54cd\u5e94\u7684 response \u8fdb\u884c\u4fee\u6539\uff0c\u4f8b\u5982\u8fdb\u884c\u52a0\u89e3\u5bc6\u7b49\u5904\u7406\u3002 \"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]} ], \"setup_hooks\" : [ \"${setup_hook_prepare_kwargs($request)}\" , \"${setup_hook_httpntlmauth($request)}\" ], \"teardown_hooks\" : [ \"${teardown_hook_sleep_N_secs($response, 2)}\" ] }","title":"\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09"},{"location":"prepare/request-hook/#hook_1","text":"hook \u51fd\u6570\u7684\u5b9a\u4e49\u653e\u7f6e\u5728\u9879\u76ee\u7684 debugtalk.py \u4e2d\uff0c\u5728 YAML/JSON \u4e2d\u8c03\u7528 hook \u51fd\u6570\u4ecd\u7136\u662f\u91c7\u7528 ${func($a, $b)} \u7684\u5f62\u5f0f\u3002 \u5bf9\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u4e0e YAML/JSON \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u5b8c\u5168\u76f8\u540c\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49\u53c2\u6570\u4f20\u53c2\u7684\u5f62\u5f0f\u6765\u5b9e\u73b0\u7075\u6d3b\u5e94\u7528\u3002 def hook_print ( msg ): print ( msg ) \u5bf9\u4e8e\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165\u4e0e\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u76f8\u5173\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 $request \u548c\u54cd\u5e94\u7684 $response \uff0c\u7528\u4e8e\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u7075\u6d3b\u5e94\u7528\u3002","title":"\u7f16\u5199 hook \u51fd\u6570"},{"location":"prepare/request-hook/#setup_hooks","text":"\u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 setup_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $request \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 request \u7684\u5168\u90e8\u5185\u5bb9\u3002\u56e0\u4e3a request \u662f\u53ef\u53d8\u53c2\u6570\u7c7b\u578b\uff08dict\uff09\uff0c\u56e0\u6b64\u8be5\u51fd\u6570\u53c2\u6570\u4e3a\u5f15\u7528\u4f20\u9012\uff0c\u5f53\u6211\u4eec\u9700\u8981\u5bf9\u8bf7\u6c42\u53c2\u6570\u8fdb\u884c\u9884\u5904\u7406\u65f6\u5c24\u5176\u6709\u7528\u3002 e.g. def setup_hook_prepare_kwargs ( request ): if request [ \"method\" ] == \"POST\" : content_type = request . get ( \"headers\" , {}) . get ( \"content-type\" ) if content_type and \"data\" in request : # if request content-type is application/json, request data should be dumped if content_type . startswith ( \"application/json\" ) and isinstance ( request [ \"data\" ], ( dict , list )): request [ \"data\" ] = json . dumps ( request [ \"data\" ]) if isinstance ( request [ \"data\" ], str ): request [ \"data\" ] = request [ \"data\" ] . encode ( 'utf-8' ) def setup_hook_httpntlmauth ( request ): if \"httpntlmauth\" in request : from requests_ntlm import HttpNtlmAuth auth_account = request . pop ( \"httpntlmauth\" ) request [ \"auth\" ] = HttpNtlmAuth ( auth_account [ \"username\" ], auth_account [ \"password\" ]) \u901a\u8fc7\u4e0a\u8ff0\u7684 setup_hook_prepare_kwargs \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0\u6839\u636e\u8bf7\u6c42\u65b9\u6cd5\u548c\u8bf7\u6c42\u7684 Content-Type \u6765\u5bf9\u8bf7\u6c42\u7684 data \u8fdb\u884c\u52a0\u5de5\u5904\u7406\uff1b\u901a\u8fc7 setup_hook_httpntlmauth \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0 HttpNtlmAuth \u6743\u9650\u6388\u6743\u3002","title":"setup_hooks"},{"location":"prepare/request-hook/#teardown_hooks","text":"\u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 teardown_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $response \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u8bf7\u6c42\u7684\u54cd\u5e94\u5b9e\u4f8b\uff08requests.Response\uff09\u3002 e.g. def teardown_hook_sleep_N_secs ( response , n_secs ): \"\"\" sleep n seconds after request \"\"\" if response . status_code == 200 : time . sleep ( 0.1 ) else : time . sleep ( n_secs ) \u901a\u8fc7\u4e0a\u8ff0\u7684 teardown_hook_sleep_N_secs \u51fd\u6570\uff0c\u53ef\u4ee5\u6839\u636e\u63a5\u53e3\u54cd\u5e94\u7684\u72b6\u6001\u7801\u6765\u8fdb\u884c\u4e0d\u540c\u65f6\u95f4\u7684\u5ef6\u8fdf\u7b49\u5f85\u3002 \u53e6\u5916\uff0c\u5728 teardown_hooks \u51fd\u6570\u4e2d\u8fd8\u53ef\u4ee5\u5bf9 response \u8fdb\u884c\u4fee\u6539\u3002\u5f53\u6211\u4eec\u9700\u8981\u5148\u5bf9\u54cd\u5e94\u5185\u5bb9\u8fdb\u884c\u5904\u7406\uff08\u4f8b\u5982\u52a0\u89e3\u5bc6\u3001\u53c2\u6570\u8fd0\u7b97\uff09\uff0c\u518d\u8fdb\u884c\u53c2\u6570\u63d0\u53d6\uff08extract\uff09\u548c\u6821\u9a8c\uff08validate\uff09\u65f6\u5c24\u5176\u6709\u7528\u3002 \u4f8b\u5982\u5728\u4e0b\u9762\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u5728\u6267\u884c\u6d4b\u8bd5\u540e\uff0c\u901a\u8fc7 teardown_hooks \u51fd\u6570\u5c06\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u548c headers \u8fdb\u884c\u4e86\u4fee\u6539\uff0c\u7136\u540e\u518d\u8fdb\u884c\u4e86\u6821\u9a8c\u3002 - test : name : alter response request : url : /headers method : GET teardown_hooks : - ${alter_response($response)} validate : - eq : [ \"status_code\" , 500 ] - eq : [ \"headers.content-type\" , \"html/text\" ] def alter_response ( response ): response . status_code = 500 response . headers [ \"Content-Type\" ] = \"html/text\"","title":"teardown_hooks"},{"location":"prepare/security/","text":"\u80cc\u666f \u00b6 \u5f88\u591a\u65f6\u5019\u9879\u76ee\u4ee3\u7801\u5728\u8fd0\u884c\u65f6\u9700\u8981\u4f7f\u7528\u5230\u8d26\u53f7\u3001\u5bc6\u7801\u3001key\u7b49\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u4f46\u662f\u4ece\u4fe1\u606f\u5b89\u5168\u7684\u89d2\u5ea6\u8003\u8651\uff0c\u6211\u4eec\u662f\u4e0d\u80fd\u5c06\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u63d0\u4ea4\u5230\u4ee3\u7801\u4ed3\u5e93\u7684\uff0c\u4e3b\u8981\u539f\u56e0\u6709\u4e24\u4e2a\uff1a \u52a0\u5f3a\u6743\u9650\u7ba1\u63a7\uff1a\u53c2\u4e0e\u9879\u76ee\u7684\u5f00\u53d1\u4eba\u5458\u53ef\u80fd\u4f1a\u6709\u5f88\u591a\uff0c\u5927\u5bb6\u90fd\u6709\u8bfb\u53d6\u4ee3\u7801\u4ed3\u5e93\u7684\u6743\u9650\uff0c\u4f46\u662f\u50cf key \u8fd9\u7c7b\u6781\u5ea6\u654f\u611f\u7684\u4fe1\u606f\u4e0d\u5e94\u8be5\u6240\u6709\u4eba\u90fd\u6709\u6743\u9650\u83b7\u53d6\uff1b \u51cf\u5c11\u4ee3\u7801\u6cc4\u6f0f\u7684\u5371\u5bb3\u6027\uff1a\u5047\u5982\u4ee3\u7801\u51fa\u73b0\u6cc4\u6f0f\uff0c\u654f\u611f\u6570\u636e\u4fe1\u606f\u4e0d\u5e94\u8be5\u4e5f\u540c\u65f6\u6cc4\u6f0f\u3002 \u89e3\u51b3\u65b9\u6848 \u00b6 \u90a3\u4ee3\u7801\u90e8\u7f72\u5230\u670d\u52a1\u5668\u6216 Jenkins \u6267\u884c\u673a\u540e\uff0c\u8fd0\u884c\u65f6\u8981\u4f7f\u7528\u5230\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u8be5\u600e\u4e48\u64cd\u4f5c\u5462\uff1f \u63a8\u8350\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff1a \u5bf9\u670d\u52a1\u5668\u8fdb\u884c\u6743\u9650\u7ba1\u63a7\uff0c\u53ea\u6709\u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\u624d\u6709\u767b\u5f55\u670d\u52a1\u5668\u7684\u6743\u9650\uff1b \u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\uff1a\u5728\u8fd0\u884c\u7684\u673a\u5668\u4e0a\u5c06\u654f\u611f\u6570\u636e\u8bbe\u7f6e\u5230\u7cfb\u7edf\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff1b \u666e\u901a\u5f00\u53d1\u4eba\u5458\uff1a\u53ea\u9700\u8981\u77e5\u9053\u654f\u611f\u4fe1\u606f\u7684\u53d8\u91cf\u540d\u79f0\uff0c\u5728\u4ee3\u7801\u4e2d\u901a\u8fc7\u8bfb\u53d6\u73af\u5883\u53d8\u91cf\u7684\u65b9\u5f0f\u83b7\u53d6\u654f\u611f\u6570\u636e\u3002 \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\uff09\u548c\u4f7f\u7528\u654f\u611f\u6570\u636e\uff08\u5f15\u7528\u73af\u5883\u53d8\u91cf\uff09\u7684\u5177\u4f53\u65b9\u6cd5\uff0c\u53ef\u53c2\u8003 \u73af\u5883\u53d8\u91cf \u4f7f\u7528\u8bf4\u660e\u6587\u6863\u3002","title":"\u4fe1\u606f\u5b89\u5168"},{"location":"prepare/security/#_1","text":"\u5f88\u591a\u65f6\u5019\u9879\u76ee\u4ee3\u7801\u5728\u8fd0\u884c\u65f6\u9700\u8981\u4f7f\u7528\u5230\u8d26\u53f7\u3001\u5bc6\u7801\u3001key\u7b49\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u4f46\u662f\u4ece\u4fe1\u606f\u5b89\u5168\u7684\u89d2\u5ea6\u8003\u8651\uff0c\u6211\u4eec\u662f\u4e0d\u80fd\u5c06\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u63d0\u4ea4\u5230\u4ee3\u7801\u4ed3\u5e93\u7684\uff0c\u4e3b\u8981\u539f\u56e0\u6709\u4e24\u4e2a\uff1a \u52a0\u5f3a\u6743\u9650\u7ba1\u63a7\uff1a\u53c2\u4e0e\u9879\u76ee\u7684\u5f00\u53d1\u4eba\u5458\u53ef\u80fd\u4f1a\u6709\u5f88\u591a\uff0c\u5927\u5bb6\u90fd\u6709\u8bfb\u53d6\u4ee3\u7801\u4ed3\u5e93\u7684\u6743\u9650\uff0c\u4f46\u662f\u50cf key \u8fd9\u7c7b\u6781\u5ea6\u654f\u611f\u7684\u4fe1\u606f\u4e0d\u5e94\u8be5\u6240\u6709\u4eba\u90fd\u6709\u6743\u9650\u83b7\u53d6\uff1b \u51cf\u5c11\u4ee3\u7801\u6cc4\u6f0f\u7684\u5371\u5bb3\u6027\uff1a\u5047\u5982\u4ee3\u7801\u51fa\u73b0\u6cc4\u6f0f\uff0c\u654f\u611f\u6570\u636e\u4fe1\u606f\u4e0d\u5e94\u8be5\u4e5f\u540c\u65f6\u6cc4\u6f0f\u3002","title":"\u80cc\u666f"},{"location":"prepare/security/#_2","text":"\u90a3\u4ee3\u7801\u90e8\u7f72\u5230\u670d\u52a1\u5668\u6216 Jenkins \u6267\u884c\u673a\u540e\uff0c\u8fd0\u884c\u65f6\u8981\u4f7f\u7528\u5230\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u8be5\u600e\u4e48\u64cd\u4f5c\u5462\uff1f \u63a8\u8350\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff1a \u5bf9\u670d\u52a1\u5668\u8fdb\u884c\u6743\u9650\u7ba1\u63a7\uff0c\u53ea\u6709\u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\u624d\u6709\u767b\u5f55\u670d\u52a1\u5668\u7684\u6743\u9650\uff1b \u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\uff1a\u5728\u8fd0\u884c\u7684\u673a\u5668\u4e0a\u5c06\u654f\u611f\u6570\u636e\u8bbe\u7f6e\u5230\u7cfb\u7edf\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff1b \u666e\u901a\u5f00\u53d1\u4eba\u5458\uff1a\u53ea\u9700\u8981\u77e5\u9053\u654f\u611f\u4fe1\u606f\u7684\u53d8\u91cf\u540d\u79f0\uff0c\u5728\u4ee3\u7801\u4e2d\u901a\u8fc7\u8bfb\u53d6\u73af\u5883\u53d8\u91cf\u7684\u65b9\u5f0f\u83b7\u53d6\u654f\u611f\u6570\u636e\u3002 \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\uff09\u548c\u4f7f\u7528\u654f\u611f\u6570\u636e\uff08\u5f15\u7528\u73af\u5883\u53d8\u91cf\uff09\u7684\u5177\u4f53\u65b9\u6cd5\uff0c\u53ef\u53c2\u8003 \u73af\u5883\u53d8\u91cf \u4f7f\u7528\u8bf4\u660e\u6587\u6863\u3002","title":"\u89e3\u51b3\u65b9\u6848"},{"location":"prepare/testcase-layer/","text":"\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b \u00b6 \u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9886\u57df\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u53ef\u7ef4\u62a4\u6027\u662f\u6781\u5176\u91cd\u8981\u7684\u56e0\u7d20\uff0c\u76f4\u63a5\u5173\u7cfb\u5230\u81ea\u52a8\u5316\u6d4b\u8bd5\u80fd\u5426\u6301\u7eed\u6709\u6548\u5730\u5728\u9879\u76ee\u4e2d\u5f00\u5c55\u3002 \u6982\u62ec\u6765\u8bf4\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\u7684\u6838\u5fc3\u662f\u5c06\u63a5\u53e3\u5b9a\u4e49\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u573a\u666f\u8fdb\u884c\u5206\u79bb\uff0c\u5355\u72ec\u8fdb\u884c\u63cf\u8ff0\u548c\u7ef4\u62a4\uff0c\u4ece\u800c\u5c3d\u53ef\u80fd\u5730\u51cf\u5c11\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7ef4\u62a4\u6210\u672c\u3002 \u903b\u8f91\u5173\u7cfb\u56fe\u5982\u4e0b\u6240\u793a\uff1a \u540c\u65f6\uff0c\u5f3a\u8c03\u5982\u4e0b\u51e0\u70b9\u6838\u5fc3\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684 \u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406 \u5982\u679c\u5bf9\u4e8e\u4e0a\u8ff0\u7b2c\u4e09\u70b9\u611f\u89c9\u96be\u4ee5\u7406\u89e3\uff0c\u4e0d\u59a8\u770b\u4e0b\u4e0a\u56fe\u4e2d\u7684\u793a\u4f8b\uff1a testcase1 \u4f9d\u8d56\u4e8e testcase2\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep12\uff09\u4e2d\u5bf9 testcase2 \u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e testcase1 \u5c31\u662f\u5b8c\u6574\u4e14\u53ef\u72ec\u7acb\u8fd0\u884c\u7684\uff1b \u5728 testsuite \u4e2d\uff0ctestcase1 \u4e0e testcase2 \u76f8\u4e92\u72ec\u7acb\uff0c\u8fd0\u884c\u987a\u5e8f\u5c31\u4e0d\u518d\u6709\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u4e86\u3002 \u5206\u5c42\u63cf\u8ff0\u8be6\u89e3 \u00b6 \u7406\u89e3\u4e86\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\uff0c\u63a5\u4e0b\u6765\u6211\u4eec\u518d\u6765\u770b\u4e0b\u5728\u5206\u5c42\u6a21\u578b\u4e0b\uff0c\u63a5\u53e3\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u3002 \u63a5\u53e3\u5b9a\u4e49\uff08API\uff09 \u00b6 \u4e3a\u4e86\u66f4\u597d\u5730\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u7ba1\u7406\uff0c\u63a8\u8350\u4f7f\u7528\u72ec\u7acb\u7684\u6587\u4ef6\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u5b58\u50a8\uff0c\u5373\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u63a5\u53e3\u63cf\u8ff0\u3002 \u63a5\u53e3\u5b9a\u4e49\u63cf\u8ff0\u7684\u4e3b\u8981\u5185\u5bb9\u5305\u62ec\uff1a name \u3001variables\u3001 request \u3001base_url\u3001validate \u7b49\uff0c\u5f62\u5f0f\u5982\u4e0b\uff1a name : get headers base_url : http://httpbin.org variables : expected_status_code : 200 request : url : /headers method : GET validate : - eq : [ \"status_code\" , $expected_status_code ] - eq : [ content.headers.Host , \"httpbin.org\" ] \u5176\u4e2d\uff0cname \u548c request \u90e8\u5206\u662f\u5fc5\u987b\u7684\uff0crequest \u4e2d\u7684\u63cf\u8ff0\u5f62\u5f0f\u4e0e requests.request \u5b8c\u5168\u76f8\u540c\u3002 \u53e6\u5916\uff0cAPI \u63cf\u8ff0\u9700\u8981\u5c3d\u91cf\u4fdd\u6301\u5b8c\u6574\uff0c\u505a\u5230\u53ef\u4ee5\u5355\u72ec\u8fd0\u884c\u3002\u5982\u679c\u5728\u63a5\u53e3\u63cf\u8ff0\u4e2d\u5b58\u5728\u53d8\u91cf\u5f15\u7528\u7684\u60c5\u51b5\uff0c\u53ef\u5728 variables \u4e2d\u5bf9\u53c2\u6570\u8fdb\u884c\u5b9a\u4e49\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5f88\u597d\u5730\u5b9e\u73b0\u5355\u4e2a\u63a5\u53e3\u7684\u8c03\u8bd5\u3002 $ hrun api/get_headers.yml INFO Start to run testcase: get headers headers INFO GET http://httpbin.org/headers INFO status_code: 200 , response_time ( ms ) : 477 .32 ms, response_length: 157 bytes . ---------------------------------------------------------------------- Ran 1 test in 0 .478s OK \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u00b6 \u5f15\u7528\u63a5\u53e3\u5b9a\u4e49 \u00b6 \u6709\u4e86\u63a5\u53e3\u7684\u5b9a\u4e49\u63cf\u8ff0\u540e\uff0c\u6211\u4eec\u7f16\u5199\u6d4b\u8bd5\u573a\u666f\u65f6\u5c31\u53ef\u4ee5\u76f4\u63a5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\u4e86\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 api \u5b57\u6bb5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94 API \u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 - config : name : \"setup and reset all.\" variables : user_agent : 'iOS/10.3' device_sn : \"TESTCASE_SETUP_XXX\" os_platform : 'ios' app_version : '2.8.6' base_url : \"http://127.0.0.1:5000\" verify : False output : - session_token - test : name : get token (setup) api : api/get_token.yml variables : user_agent : 'iOS/10.3' device_sn : $device_sn os_platform : 'ios' app_version : '2.8.6' extract : - session_token : content.token validate : - eq : [ \"status_code\" , 200 ] - len_eq : [ \"content.token\" , 16 ] - test : name : reset all users api : api/reset_all.yml variables : token : $session_token \u82e5\u9700\u8981\u63a7\u5236\u6216\u6539\u53d8\u63a5\u53e3\u5b9a\u4e49\u4e2d\u7684\u53c2\u6570\u503c\uff0c\u53ef\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u6307\u5b9a variables \u53c2\u6570\uff0c\u8986\u76d6 API \u4e2d\u7684 variables \u5b9e\u73b0\u3002 \u540c\u6837\u5730\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49 validate \u540e\uff0c\u4e5f\u4f1a\u4e0e API \u4e2d\u7684 validate \u5408\u5e76\u8986\u76d6\u3002\u56e0\u6b64\u63a8\u8350\u7684\u505a\u6cd5\u662f\uff0c\u5728 API \u5b9a\u4e49\u4e2d\u7684 validate \u53ea\u63cf\u8ff0\u6700\u57fa\u672c\u7684\u6821\u9a8c\u9879\uff0c\u4f8b\u5982 status_code\uff0c\u5bf9\u4e8e\u4e0e\u4e1a\u52a1\u903b\u8f91\u76f8\u5173\u7684\u66f4\u591a\u6821\u9a8c\u9879\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u8fdb\u884c\u63cf\u8ff0\u3002 \u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u5728\u6d4b\u8bd5\u7528\u4f8b\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u9664\u4e86\u53ef\u4ee5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u8fd8\u53ef\u4ee5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5728\u907f\u514d\u91cd\u590d\u63cf\u8ff0\u7684\u540c\u65f6\uff0c\u89e3\u51b3\u6d4b\u8bd5\u7528\u4f8b\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u4ece\u800c\u4fdd\u8bc1\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u72ec\u7acb\u53ef\u8fd0\u884c\u7684\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 testcase \u5b57\u6bb5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 \u4f8b\u5982\uff0c\u5728\u4e0a\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\"setup and reset all.\"\uff09\u4e2d\uff0c\u5b9e\u73b0\u4e86\u5bf9\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\uff1b\u540c\u65f6\uff0c\u5728\u5f88\u591a\u5176\u5b83\u529f\u80fd\u4e2d\u90fd\u4f1a\u4f9d\u8d56\u4e8e\u83b7\u53d6 token \u7684\u529f\u80fd\uff0c\u5982\u679c\u5c06\u8be5\u529f\u80fd\u7684\u6d4b\u8bd5\u6b65\u9aa4\u811a\u672c\u62f7\u8d1d\u5230\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u90a3\u4e48\u5c31\u4f1a\u5b58\u5728\u5927\u91cf\u91cd\u590d\uff0c\u5f53\u9700\u8981\u5bf9\u8be5\u90e8\u5206\u8fdb\u884c\u4fee\u6539\u65f6\u5c31\u9700\u8981\u4fee\u6539\u6240\u6709\u5730\u65b9\uff0c\u663e\u7136\u4e0d\u4fbf\u4e8e\u7ef4\u62a4\u3002 \u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5728\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\u5982\u521b\u5efa\u7528\u6237\uff09\u4e2d\uff0c\u5f15\u7528\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08testcases/setup.yml\uff09\u4f5c\u4e3a\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4ece\u800c\u521b\u5efa\u7528\u6237\uff08\"create user and check result.\"\uff09\u8fd9\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u53d8\u5f97\u72ec\u7acb\u53ef\u8fd0\u884c\u4e86\u3002 - config : name : \"create user and check result.\" id : create_user base_url : \"http://127.0.0.1:5000\" variables : uid : 9001 device_sn : \"TESTCASE_CREATE_XXX\" output : - session_token - test : name : setup and reset all (override) for $device_sn. testcase : testcases/setup.yml output : - session_token - test : name : create user and check result. variables : token : $session_token testcase : testcases/deps/check_and_create.yml \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09 \u00b6 \u5f53\u6d4b\u8bd5\u7528\u4f8b\u6570\u91cf\u6bd4\u8f83\u591a\u4ee5\u540e\uff0c\u4e3a\u4e86\u65b9\u4fbf\u7ba1\u7406\u548c\u5b9e\u73b0\u6279\u91cf\u8fd0\u884c\uff0c\u901a\u5e38\u9700\u8981\u4f7f\u7528\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6765\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u7ec4\u7ec7\u3002 \u5728\u524d\u6587\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\u4e2d\u4e5f\u5f3a\u8c03\u4e86\uff0c\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406\u3002 \u56e0\u4e3a\u662f \u65e0\u5e8f \u96c6\u5408\uff0c\u56e0\u6b64\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u4f1a\u4e0e\u6d4b\u8bd5\u7528\u4f8b\u6709\u4e9b\u4e0d\u540c\uff0c\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6587\u4ef6\u4e2d\uff0c\u7b2c\u4e00\u5c42\u7ea7\u5b58\u5728\u4e24\u7c7b\u5b57\u6bb5\uff1a config: \u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u603b\u4f53\u914d\u7f6e\u53c2\u6570 testcases: \u503c\u4e3a\u5b57\u5178\u7ed3\u6784\uff08\u65e0\u5e8f\uff09\uff0ckey \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0cvalue \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5185\u5bb9\uff1b\u5728\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u65f6\u4e5f\u53ef\u4ee5\u6307\u5b9a variables\uff0c\u5b9e\u73b0\u5bf9\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u4e2d variables \u7684\u8986\u76d6\u3002 \u975e\u53c2\u6570\u5316\u573a\u666f \u00b6 config : name : create users with uid variables : device_sn : ${gen_random_string(15)} var_a : ${gen_random_string(5)} var_b : $var_a base_url : \"http://127.0.0.1:5000\" testcases : create user 1000 and check result. : testcase : testcases/create_user.yml variables : uid : 1000 var_c : ${gen_random_string(5)} var_d : $var_c create user 1001 and check result. : testcase : testcases/create_user.yml variables : uid : 1001 var_c : ${gen_random_string(5)} var_d : $var_c \u53c2\u6570\u5316\u573a\u666f\uff08parameters\uff09 \u00b6 \u5bf9\u4e8e\u53c2\u6570\u5316\u573a\u666f\uff0c\u53ef\u901a\u8fc7 parameters \u5b9e\u73b0\uff0c\u63cf\u8ff0\u5f62\u5f0f\u5982\u4e0b\u6240\u793a\u3002 config : name : create users with parameters variables : device_sn : ${gen_random_string(15)} base_url : \"http://127.0.0.1:5000\" testcases : create user $uid and check result for $device_sn. : testcase : testcases/create_user.yml variables : uid : 1000 device_sn : TESTSUITE_XXX parameters : uid : [ 101 , 102 , 103 ] device_sn : [ TESTSUITE_X1 , TESTSUITE_X2 ] \u53c2\u6570\u5316\u540e\uff0cparameters \u4e2d\u7684\u53d8\u91cf\u5c06\u91c7\u7528\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\u5f62\u6210\u53c2\u6570\u5217\u8868\uff0c\u4f9d\u6b21\u8986\u76d6 variables \u4e2d\u7684\u53c2\u6570\uff0c\u9a71\u52a8\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u3002 \u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u7ba1\u7406 && \u811a\u624b\u67b6\u5de5\u5177 \u00b6 \u5728\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u7ec4\u7ec7\u7ba1\u7406\u65f6\uff0c\u5bf9\u4e8e\u6587\u4ef6\u7684\u5b58\u50a8\u4f4d\u7f6e\u5747\u6ca1\u6709\u8981\u6c42\u548c\u9650\u5236\uff0c\u5728\u5f15\u7528\u65f6\u53ea\u9700\u8981\u6307\u5b9a\u5bf9\u5e94\u7684\u6587\u4ef6\u8def\u5f84\u5373\u53ef\u3002\u4f46\u4ece\u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e\u7684\u89d2\u5ea6\uff0c\u6700\u597d\u662f\u6309\u7167\u63a8\u8350\u7684\u6587\u4ef6\u5939\u540d\u79f0\u8fdb\u884c\u5b58\u50a8\u7ba1\u7406\uff0c\u5e76\u53ef\u901a\u8fc7\u5b50\u76ee\u5f55\u5b9e\u73b0\u9879\u76ee\u6a21\u5757\u5206\u7c7b\u7ba1\u7406\u3002 \u63a8\u8350\u7684\u65b9\u5f0f\u6c47\u603b\u5982\u4e0b\uff1a debugtalk.py \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u5047\u8bbe\u4e3a PRJ_ROOT_DIR .env \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/.env \u63a5\u53e3\u5b9a\u4e49\uff08API\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/api/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testcases/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u6587\u4ef6\u5fc5\u987b\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testsuites/ \u76ee\u5f55\u4e0b data \u6587\u4ef6\u5939\uff1a\u5b58\u50a8\u53c2\u6570\u5316\u6587\u4ef6\uff0c\u6216\u8005\u9879\u76ee\u4f9d\u8d56\u7684\u6587\u4ef6\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/data/ reports \u6587\u4ef6\u5939\uff1a\u5b58\u50a8 \bHTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u751f\u6210\u8def\u5f84\u4e3a PRJ_ROOT_DIR/reports/ \u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a $ tree tests tests \u251c\u2500\u2500 .env \u251c\u2500\u2500 data \u2502 \u251c\u2500\u2500 app_version.csv \u2502 \u2514\u2500\u2500 account.csv \u251c\u2500\u2500 api \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 get_headers.yml \u2502 \u251c\u2500\u2500 get_token.yml \u2502 \u251c\u2500\u2500 get_user.yml \u2502 \u2514\u2500\u2500 reset_all.yml \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 testcases \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 deps \u2502 \u2502 \u2514\u2500\u2500 check_and_create.yml \u2502 \u2514\u2500\u2500 setup.yml \u2514\u2500\u2500 testsuites \u251c\u2500\u2500 create_users.yml \u2514\u2500\u2500 create_users_with_parameters.yml \u9879\u76ee\u811a\u624b\u67b6 \u540c\u65f6\uff0c\u5728 HttpRunner \u4e2d\u5b9e\u73b0\u4e86\u4e00\u4e2a\u811a\u624b\u67b6\u5de5\u5177\uff0c\u53ef\u4ee5\u5feb\u901f\u521b\u5efa\u9879\u76ee\u7684\u76ee\u5f55\u7ed3\u6784\u3002\u8be5\u60f3\u6cd5\u6765\u6e90\u4e8e Django \u7684 django-admin.py startproject project_name \u3002 \u4f7f\u7528\u65b9\u5f0f\u4e5f\u4e0e Django \u7c7b\u4f3c\uff0c\u53ea\u9700\u8981\u901a\u8fc7 --startproject \u6307\u5b9a\u65b0\u9879\u76ee\u7684\u540d\u79f0\u5373\u53ef\u3002 $ hrun --startproject demo Start to create new project: demo CWD: /Users/debugtalk/MyProjects/examples created folder: demo created folder: demo/api created folder: demo/testcases created folder: demo/testsuites created folder: demo/reports created file: demo/debugtalk.py created file: demo/.env \u76f8\u5173\u53c2\u8003 \u00b6 \u300aHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff08\u5df2\u8fc7\u671f\uff09\u300b \u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u8be6\u7ec6\u793a\u4f8b\uff1a HttpRunner/tests","title":"\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42"},{"location":"prepare/testcase-layer/#_1","text":"\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9886\u57df\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u53ef\u7ef4\u62a4\u6027\u662f\u6781\u5176\u91cd\u8981\u7684\u56e0\u7d20\uff0c\u76f4\u63a5\u5173\u7cfb\u5230\u81ea\u52a8\u5316\u6d4b\u8bd5\u80fd\u5426\u6301\u7eed\u6709\u6548\u5730\u5728\u9879\u76ee\u4e2d\u5f00\u5c55\u3002 \u6982\u62ec\u6765\u8bf4\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\u7684\u6838\u5fc3\u662f\u5c06\u63a5\u53e3\u5b9a\u4e49\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u573a\u666f\u8fdb\u884c\u5206\u79bb\uff0c\u5355\u72ec\u8fdb\u884c\u63cf\u8ff0\u548c\u7ef4\u62a4\uff0c\u4ece\u800c\u5c3d\u53ef\u80fd\u5730\u51cf\u5c11\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7ef4\u62a4\u6210\u672c\u3002 \u903b\u8f91\u5173\u7cfb\u56fe\u5982\u4e0b\u6240\u793a\uff1a \u540c\u65f6\uff0c\u5f3a\u8c03\u5982\u4e0b\u51e0\u70b9\u6838\u5fc3\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684 \u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406 \u5982\u679c\u5bf9\u4e8e\u4e0a\u8ff0\u7b2c\u4e09\u70b9\u611f\u89c9\u96be\u4ee5\u7406\u89e3\uff0c\u4e0d\u59a8\u770b\u4e0b\u4e0a\u56fe\u4e2d\u7684\u793a\u4f8b\uff1a testcase1 \u4f9d\u8d56\u4e8e testcase2\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep12\uff09\u4e2d\u5bf9 testcase2 \u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e testcase1 \u5c31\u662f\u5b8c\u6574\u4e14\u53ef\u72ec\u7acb\u8fd0\u884c\u7684\uff1b \u5728 testsuite \u4e2d\uff0ctestcase1 \u4e0e testcase2 \u76f8\u4e92\u72ec\u7acb\uff0c\u8fd0\u884c\u987a\u5e8f\u5c31\u4e0d\u518d\u6709\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u4e86\u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b"},{"location":"prepare/testcase-layer/#_2","text":"\u7406\u89e3\u4e86\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\uff0c\u63a5\u4e0b\u6765\u6211\u4eec\u518d\u6765\u770b\u4e0b\u5728\u5206\u5c42\u6a21\u578b\u4e0b\uff0c\u63a5\u53e3\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u3002","title":"\u5206\u5c42\u63cf\u8ff0\u8be6\u89e3"},{"location":"prepare/testcase-layer/#api","text":"\u4e3a\u4e86\u66f4\u597d\u5730\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u7ba1\u7406\uff0c\u63a8\u8350\u4f7f\u7528\u72ec\u7acb\u7684\u6587\u4ef6\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u5b58\u50a8\uff0c\u5373\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u63a5\u53e3\u63cf\u8ff0\u3002 \u63a5\u53e3\u5b9a\u4e49\u63cf\u8ff0\u7684\u4e3b\u8981\u5185\u5bb9\u5305\u62ec\uff1a name \u3001variables\u3001 request \u3001base_url\u3001validate \u7b49\uff0c\u5f62\u5f0f\u5982\u4e0b\uff1a name : get headers base_url : http://httpbin.org variables : expected_status_code : 200 request : url : /headers method : GET validate : - eq : [ \"status_code\" , $expected_status_code ] - eq : [ content.headers.Host , \"httpbin.org\" ] \u5176\u4e2d\uff0cname \u548c request \u90e8\u5206\u662f\u5fc5\u987b\u7684\uff0crequest \u4e2d\u7684\u63cf\u8ff0\u5f62\u5f0f\u4e0e requests.request \u5b8c\u5168\u76f8\u540c\u3002 \u53e6\u5916\uff0cAPI \u63cf\u8ff0\u9700\u8981\u5c3d\u91cf\u4fdd\u6301\u5b8c\u6574\uff0c\u505a\u5230\u53ef\u4ee5\u5355\u72ec\u8fd0\u884c\u3002\u5982\u679c\u5728\u63a5\u53e3\u63cf\u8ff0\u4e2d\u5b58\u5728\u53d8\u91cf\u5f15\u7528\u7684\u60c5\u51b5\uff0c\u53ef\u5728 variables \u4e2d\u5bf9\u53c2\u6570\u8fdb\u884c\u5b9a\u4e49\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5f88\u597d\u5730\u5b9e\u73b0\u5355\u4e2a\u63a5\u53e3\u7684\u8c03\u8bd5\u3002 $ hrun api/get_headers.yml INFO Start to run testcase: get headers headers INFO GET http://httpbin.org/headers INFO status_code: 200 , response_time ( ms ) : 477 .32 ms, response_length: 157 bytes . ---------------------------------------------------------------------- Ran 1 test in 0 .478s OK","title":"\u63a5\u53e3\u5b9a\u4e49\uff08API\uff09"},{"location":"prepare/testcase-layer/#testcase","text":"","title":"\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09"},{"location":"prepare/testcase-layer/#_3","text":"\u6709\u4e86\u63a5\u53e3\u7684\u5b9a\u4e49\u63cf\u8ff0\u540e\uff0c\u6211\u4eec\u7f16\u5199\u6d4b\u8bd5\u573a\u666f\u65f6\u5c31\u53ef\u4ee5\u76f4\u63a5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\u4e86\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 api \u5b57\u6bb5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94 API \u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 - config : name : \"setup and reset all.\" variables : user_agent : 'iOS/10.3' device_sn : \"TESTCASE_SETUP_XXX\" os_platform : 'ios' app_version : '2.8.6' base_url : \"http://127.0.0.1:5000\" verify : False output : - session_token - test : name : get token (setup) api : api/get_token.yml variables : user_agent : 'iOS/10.3' device_sn : $device_sn os_platform : 'ios' app_version : '2.8.6' extract : - session_token : content.token validate : - eq : [ \"status_code\" , 200 ] - len_eq : [ \"content.token\" , 16 ] - test : name : reset all users api : api/reset_all.yml variables : token : $session_token \u82e5\u9700\u8981\u63a7\u5236\u6216\u6539\u53d8\u63a5\u53e3\u5b9a\u4e49\u4e2d\u7684\u53c2\u6570\u503c\uff0c\u53ef\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u6307\u5b9a variables \u53c2\u6570\uff0c\u8986\u76d6 API \u4e2d\u7684 variables \u5b9e\u73b0\u3002 \u540c\u6837\u5730\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49 validate \u540e\uff0c\u4e5f\u4f1a\u4e0e API \u4e2d\u7684 validate \u5408\u5e76\u8986\u76d6\u3002\u56e0\u6b64\u63a8\u8350\u7684\u505a\u6cd5\u662f\uff0c\u5728 API \u5b9a\u4e49\u4e2d\u7684 validate \u53ea\u63cf\u8ff0\u6700\u57fa\u672c\u7684\u6821\u9a8c\u9879\uff0c\u4f8b\u5982 status_code\uff0c\u5bf9\u4e8e\u4e0e\u4e1a\u52a1\u903b\u8f91\u76f8\u5173\u7684\u66f4\u591a\u6821\u9a8c\u9879\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u8fdb\u884c\u63cf\u8ff0\u3002","title":"\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49"},{"location":"prepare/testcase-layer/#_4","text":"\u5728\u6d4b\u8bd5\u7528\u4f8b\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u9664\u4e86\u53ef\u4ee5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u8fd8\u53ef\u4ee5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5728\u907f\u514d\u91cd\u590d\u63cf\u8ff0\u7684\u540c\u65f6\uff0c\u89e3\u51b3\u6d4b\u8bd5\u7528\u4f8b\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u4ece\u800c\u4fdd\u8bc1\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u72ec\u7acb\u53ef\u8fd0\u884c\u7684\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 testcase \u5b57\u6bb5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 \u4f8b\u5982\uff0c\u5728\u4e0a\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\"setup and reset all.\"\uff09\u4e2d\uff0c\u5b9e\u73b0\u4e86\u5bf9\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\uff1b\u540c\u65f6\uff0c\u5728\u5f88\u591a\u5176\u5b83\u529f\u80fd\u4e2d\u90fd\u4f1a\u4f9d\u8d56\u4e8e\u83b7\u53d6 token \u7684\u529f\u80fd\uff0c\u5982\u679c\u5c06\u8be5\u529f\u80fd\u7684\u6d4b\u8bd5\u6b65\u9aa4\u811a\u672c\u62f7\u8d1d\u5230\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u90a3\u4e48\u5c31\u4f1a\u5b58\u5728\u5927\u91cf\u91cd\u590d\uff0c\u5f53\u9700\u8981\u5bf9\u8be5\u90e8\u5206\u8fdb\u884c\u4fee\u6539\u65f6\u5c31\u9700\u8981\u4fee\u6539\u6240\u6709\u5730\u65b9\uff0c\u663e\u7136\u4e0d\u4fbf\u4e8e\u7ef4\u62a4\u3002 \u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5728\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\u5982\u521b\u5efa\u7528\u6237\uff09\u4e2d\uff0c\u5f15\u7528\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08testcases/setup.yml\uff09\u4f5c\u4e3a\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4ece\u800c\u521b\u5efa\u7528\u6237\uff08\"create user and check result.\"\uff09\u8fd9\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u53d8\u5f97\u72ec\u7acb\u53ef\u8fd0\u884c\u4e86\u3002 - config : name : \"create user and check result.\" id : create_user base_url : \"http://127.0.0.1:5000\" variables : uid : 9001 device_sn : \"TESTCASE_CREATE_XXX\" output : - session_token - test : name : setup and reset all (override) for $device_sn. testcase : testcases/setup.yml output : - session_token - test : name : create user and check result. variables : token : $session_token testcase : testcases/deps/check_and_create.yml","title":"\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b"},{"location":"prepare/testcase-layer/#testsuite","text":"\u5f53\u6d4b\u8bd5\u7528\u4f8b\u6570\u91cf\u6bd4\u8f83\u591a\u4ee5\u540e\uff0c\u4e3a\u4e86\u65b9\u4fbf\u7ba1\u7406\u548c\u5b9e\u73b0\u6279\u91cf\u8fd0\u884c\uff0c\u901a\u5e38\u9700\u8981\u4f7f\u7528\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6765\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u7ec4\u7ec7\u3002 \u5728\u524d\u6587\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\u4e2d\u4e5f\u5f3a\u8c03\u4e86\uff0c\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406\u3002 \u56e0\u4e3a\u662f \u65e0\u5e8f \u96c6\u5408\uff0c\u56e0\u6b64\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u4f1a\u4e0e\u6d4b\u8bd5\u7528\u4f8b\u6709\u4e9b\u4e0d\u540c\uff0c\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6587\u4ef6\u4e2d\uff0c\u7b2c\u4e00\u5c42\u7ea7\u5b58\u5728\u4e24\u7c7b\u5b57\u6bb5\uff1a config: \u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u603b\u4f53\u914d\u7f6e\u53c2\u6570 testcases: \u503c\u4e3a\u5b57\u5178\u7ed3\u6784\uff08\u65e0\u5e8f\uff09\uff0ckey \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0cvalue \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5185\u5bb9\uff1b\u5728\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u65f6\u4e5f\u53ef\u4ee5\u6307\u5b9a variables\uff0c\u5b9e\u73b0\u5bf9\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u4e2d variables \u7684\u8986\u76d6\u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09"},{"location":"prepare/testcase-layer/#_5","text":"config : name : create users with uid variables : device_sn : ${gen_random_string(15)} var_a : ${gen_random_string(5)} var_b : $var_a base_url : \"http://127.0.0.1:5000\" testcases : create user 1000 and check result. : testcase : testcases/create_user.yml variables : uid : 1000 var_c : ${gen_random_string(5)} var_d : $var_c create user 1001 and check result. : testcase : testcases/create_user.yml variables : uid : 1001 var_c : ${gen_random_string(5)} var_d : $var_c","title":"\u975e\u53c2\u6570\u5316\u573a\u666f"},{"location":"prepare/testcase-layer/#parameters","text":"\u5bf9\u4e8e\u53c2\u6570\u5316\u573a\u666f\uff0c\u53ef\u901a\u8fc7 parameters \u5b9e\u73b0\uff0c\u63cf\u8ff0\u5f62\u5f0f\u5982\u4e0b\u6240\u793a\u3002 config : name : create users with parameters variables : device_sn : ${gen_random_string(15)} base_url : \"http://127.0.0.1:5000\" testcases : create user $uid and check result for $device_sn. : testcase : testcases/create_user.yml variables : uid : 1000 device_sn : TESTSUITE_XXX parameters : uid : [ 101 , 102 , 103 ] device_sn : [ TESTSUITE_X1 , TESTSUITE_X2 ] \u53c2\u6570\u5316\u540e\uff0cparameters \u4e2d\u7684\u53d8\u91cf\u5c06\u91c7\u7528\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\u5f62\u6210\u53c2\u6570\u5217\u8868\uff0c\u4f9d\u6b21\u8986\u76d6 variables \u4e2d\u7684\u53c2\u6570\uff0c\u9a71\u52a8\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u3002","title":"\u53c2\u6570\u5316\u573a\u666f\uff08parameters\uff09"},{"location":"prepare/testcase-layer/#_6","text":"\u5728\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u7ec4\u7ec7\u7ba1\u7406\u65f6\uff0c\u5bf9\u4e8e\u6587\u4ef6\u7684\u5b58\u50a8\u4f4d\u7f6e\u5747\u6ca1\u6709\u8981\u6c42\u548c\u9650\u5236\uff0c\u5728\u5f15\u7528\u65f6\u53ea\u9700\u8981\u6307\u5b9a\u5bf9\u5e94\u7684\u6587\u4ef6\u8def\u5f84\u5373\u53ef\u3002\u4f46\u4ece\u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e\u7684\u89d2\u5ea6\uff0c\u6700\u597d\u662f\u6309\u7167\u63a8\u8350\u7684\u6587\u4ef6\u5939\u540d\u79f0\u8fdb\u884c\u5b58\u50a8\u7ba1\u7406\uff0c\u5e76\u53ef\u901a\u8fc7\u5b50\u76ee\u5f55\u5b9e\u73b0\u9879\u76ee\u6a21\u5757\u5206\u7c7b\u7ba1\u7406\u3002 \u63a8\u8350\u7684\u65b9\u5f0f\u6c47\u603b\u5982\u4e0b\uff1a debugtalk.py \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u5047\u8bbe\u4e3a PRJ_ROOT_DIR .env \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/.env \u63a5\u53e3\u5b9a\u4e49\uff08API\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/api/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testcases/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u6587\u4ef6\u5fc5\u987b\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testsuites/ \u76ee\u5f55\u4e0b data \u6587\u4ef6\u5939\uff1a\u5b58\u50a8\u53c2\u6570\u5316\u6587\u4ef6\uff0c\u6216\u8005\u9879\u76ee\u4f9d\u8d56\u7684\u6587\u4ef6\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/data/ reports \u6587\u4ef6\u5939\uff1a\u5b58\u50a8 \bHTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u751f\u6210\u8def\u5f84\u4e3a PRJ_ROOT_DIR/reports/ \u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a $ tree tests tests \u251c\u2500\u2500 .env \u251c\u2500\u2500 data \u2502 \u251c\u2500\u2500 app_version.csv \u2502 \u2514\u2500\u2500 account.csv \u251c\u2500\u2500 api \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 get_headers.yml \u2502 \u251c\u2500\u2500 get_token.yml \u2502 \u251c\u2500\u2500 get_user.yml \u2502 \u2514\u2500\u2500 reset_all.yml \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 testcases \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 deps \u2502 \u2502 \u2514\u2500\u2500 check_and_create.yml \u2502 \u2514\u2500\u2500 setup.yml \u2514\u2500\u2500 testsuites \u251c\u2500\u2500 create_users.yml \u2514\u2500\u2500 create_users_with_parameters.yml \u9879\u76ee\u811a\u624b\u67b6 \u540c\u65f6\uff0c\u5728 HttpRunner \u4e2d\u5b9e\u73b0\u4e86\u4e00\u4e2a\u811a\u624b\u67b6\u5de5\u5177\uff0c\u53ef\u4ee5\u5feb\u901f\u521b\u5efa\u9879\u76ee\u7684\u76ee\u5f55\u7ed3\u6784\u3002\u8be5\u60f3\u6cd5\u6765\u6e90\u4e8e Django \u7684 django-admin.py startproject project_name \u3002 \u4f7f\u7528\u65b9\u5f0f\u4e5f\u4e0e Django \u7c7b\u4f3c\uff0c\u53ea\u9700\u8981\u901a\u8fc7 --startproject \u6307\u5b9a\u65b0\u9879\u76ee\u7684\u540d\u79f0\u5373\u53ef\u3002 $ hrun --startproject demo Start to create new project: demo CWD: /Users/debugtalk/MyProjects/examples created folder: demo created folder: demo/api created folder: demo/testcases created folder: demo/testsuites created folder: demo/reports created file: demo/debugtalk.py created file: demo/.env","title":"\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u7ba1\u7406 && \u811a\u624b\u67b6\u5de5\u5177"},{"location":"prepare/testcase-layer/#_7","text":"\u300aHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff08\u5df2\u8fc7\u671f\uff09\u300b \u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u8be6\u7ec6\u793a\u4f8b\uff1a HttpRunner/tests","title":"\u76f8\u5173\u53c2\u8003"},{"location":"prepare/testcase-structure/","text":"YAML & JSON \u00b6 HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u652f\u6301\u4e24\u79cd\u6587\u4ef6\u683c\u5f0f\uff1aYAML \u548c JSON\u3002 JSON \u548c YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u5b8c\u5168\u7b49\u4ef7\uff0c\u5305\u542b\u7684\u4fe1\u606f\u5185\u5bb9\u4e5f\u5b8c\u5168\u76f8\u540c\u3002 \u5bf9\u4e8e\u65b0\u624b\u6765\u8bf4\uff0c\u63a8\u8350\u4f7f\u7528 JSON \u683c\u5f0f\uff0c\u867d\u7136\u63cf\u8ff0\u5f62\u5f0f\u4e0a\u7a0d\u663e\u7d2f\u8d58\uff0c\u4f46\u662f\u4e0d\u5bb9\u6613\u51fa\u9519\uff08\u5927\u591a\u7f16\u8f91\u5668\u90fd\u5177\u6709 JSON \u683c\u5f0f\u7684\u68c0\u6d4b\u529f\u80fd\uff09\uff1b\u540c\u65f6\uff0cHttpRunner \u4e5f\u5185\u7f6e\u4e86 JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b\u548c\u6837\u5f0f\u7f8e\u5316\u529f\u80fd\uff0c\u8be6\u60c5\u53ef\u67e5\u770b \u300aValidate & Prettify\u300b \u3002 \u5bf9\u4e8e\u719f\u6089 YAML \u683c\u5f0f\u7684\u4eba\u6765\u8bf4\uff0c\u7f16\u5199\u7ef4\u62a4 YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4f1a\u66f4\u7b80\u6d01\uff0c\u4f46\u524d\u63d0\u662f\u8981\u4fdd\u8bc1 YAML \u683c\u5f0f\u6ca1\u6709\u8bed\u6cd5\u9519\u8bef\u3002 \u5bf9\u4e8e\u4e24\u79cd\u683c\u5f0f\u7684\u5c55\u793a\u5dee\u5f02\uff0c\u53ef\u4ee5\u5bf9\u6bd4\u67e5\u770b demo-quickstart-6.json \u548c demo-quickstart-6.yml \u83b7\u53d6\u521d\u6b65\u7684\u5370\u8c61\u3002 \u540e\u9762\u4e3a\u4e86\u66f4\u6e05\u6670\u7684\u63cf\u8ff0\uff0c\u7edf\u4e00\u91c7\u7528 JSON \u683c\u5f0f\u4f5c\u4e3a\u793a\u4f8b\u3002 \u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784 \u00b6 \u5728 HttpRunner \u4e2d\uff0c\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u4e3b\u8981\u57fa\u4e8e\u4e09\u4e2a\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a\u6587\u4ef6\u5939\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08 YAML/JSON \uff09\u6587\u4ef6 \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a YAML/JSON \u6587\u4ef6\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff1a\u5bf9\u5e94 YAML/JSON \u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a test \uff0c\b\u63cf\u8ff0\u5355\u6b21\u63a5\u53e3\u6d4b\u8bd5\u7684\u5168\u90e8\u5185\u5bb9\uff0c\u5305\u62ec\u53d1\u8d77\u63a5\u53e3\u8bf7\u6c42\u3001\u89e3\u6790\u54cd\u5e94\u7ed3\u679c\u3001\u6821\u9a8c\u7ed3\u679c\u7b49 \u5bf9\u4e8e\u5355\u4e2a YAML/JSON \u6587\u4ef6\u6765\u8bf4\uff0c\u6570\u636e\u5b58\u50a8\u7ed3\u6784\u4e3a list of dict \u7684\u5f62\u5f0f\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u4e00\u4e2a\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u3002 \u5177\u4f53\u5730\uff1a config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879 test\uff1a\u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5b58\u5728\u987a\u5e8f\u5173\u7cfb\uff0c\u8fd0\u884c\u65f6\u5c06\u4ece\u524d\u5f80\u540e\u4f9d\u6b21\u8fd0\u884c\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u5bf9\u5e94\u7684 JSON \u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { ... } }, { \"test\" : { ... } }, { \"test\" : { ... } } ] \u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f5c\u7528\u57df \u00b6 \u5728\u6d4b\u8bd5\u7528\u4f8b\u5185\u90e8\uff0cHttpRunner \u5212\u5206\u4e86\u4e24\u5c42\u53d8\u91cf\u7a7a\u95f4\u4f5c\u7528\u57df\uff08context\uff09\u3002 config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff1b test\uff1a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f1a\u7ee7\u627f\u6216\u8986\u76d6 config \u4e2d\u5b9a\u4e49\u7684\u5185\u5bb9\uff1b \u82e5\u67d0\u53d8\u91cf\u5728 config \u4e2d\u5b9a\u4e49\u4e86\uff0c\u5728\u67d0 test \u4e2d\u6ca1\u6709\u5b9a\u4e49\uff0c\u5219\u8be5 test \u4f1a\u7ee7\u627f\u8be5\u53d8\u91cf \u82e5\u67d0\u53d8\u91cf\u5728 config \u548c\u67d0 test \u4e2d\u90fd\u5b9a\u4e49\u4e86\uff0c\u5219\u8be5 test \u4e2d\u4f7f\u7528\u81ea\u5df1\u5b9a\u4e49\u7684\u53d8\u91cf\u503c \u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u7684\u53d8\u91cf\u7a7a\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u4e92\u4e0d\u5f71\u54cd\uff1b \u5982\u9700\u5728\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\u4f20\u9012\u53c2\u6570\u503c\uff0c\u5219\u9700\u8981\u4f7f\u7528 extract \u5173\u952e\u5b57\uff0c\u5e76\u4e14\u53ea\u80fd\u4ece\u524d\u5f80\u540e\u4f20\u9012 config \u00b6 \"config\" : { \"name\" : \"testcase description\" , \"parameters\" : [ { \"user_agent\" : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ]}, { \"app_version\" : \"${P(app_version.csv)}\" }, { \"os_platform\" : \"${get_os_platform()}\" } ], \"variables\" : [ { \"user_agent\" : \"iOS/10.3\" }, { \"device_sn\" : \"${gen_random_string(15)}\" }, { \"os_platform\" : \"ios\" } ], \"request\" : { \"base_url\" : \"http://127.0.0.1:5000\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"$device_sn\" } }, \"output\" : [ \"token\" ] } Key required? format descrption name Yes string \u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6807\u9898 variables No list of dict \u5b9a\u4e49\u7684\u5168\u5c40\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b parameters No list of dict \u5168\u5c40\u53c2\u6570\uff0c\u7528\u4e8e\u5b9e\u73b0\u6570\u636e\u5316\u9a71\u52a8\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b request No dict request \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b\uff1b\u5e38\u7528\u53c2\u6570\u5305\u62ec base_url \u548c headers request Key required? format descrption base_url No string \u6d4b\u8bd5\u7528\u4f8b\u8bf7\u6c42 URL \u7684\u516c\u5171 host\uff0c\u6307\u5b9a\u8be5\u53c2\u6570\u540e\uff0ctest \u4e2d\u7684 url \u53ef\u4ee5\u53ea\u63cf\u8ff0 path \u90e8\u5206 headers No dict request \u4e2d headers \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b output No list \u6574\u4e2a\u7528\u4f8b\u8f93\u51fa\u7684\u53c2\u6570\u5217\u8868\uff0c\u53ef\u8f93\u51fa\u7684\u53c2\u6570\u5305\u62ec\u516c\u5171\u7684 variable \u548c extract \u7684\u53c2\u6570; \u5728 log-level \u4e3a debug \u6a21\u5f0f\u4e0b\uff0c\u4f1a\u5728 terminal \u4e2d\u6253\u5370\u51fa\u53c2\u6570\u5185\u5bb9 test \u00b6 \"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ], \"setup_hooks\" : [], \"teardown_hooks\" : [] } } Key required? format descrption name Yes string \u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0 request Yes dict HTTP \u8bf7\u6c42\u7684\u8be6\u7ec6\u5185\u5bb9\uff1b\u53ef\u7528\u53c2\u6570\u8be6\u89c1 python-requests \u5b98\u65b9\u6587\u6863 variables No list of dict \u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 extract No list \u4ece\u5f53\u524d HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5e76\u4fdd\u5b58\u5230\u53c2\u6570\u53d8\u91cf\u4e2d\uff08\u4f8b\u5982 token \uff09\uff0c\u540e\u7eed\u6d4b\u8bd5\u7528\u4f8b\u53ef\u901a\u8fc7 $token \u7684\u5f62\u5f0f\u8fdb\u884c\u5f15\u7528 validate No list \u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u7684\u7ed3\u679c\u6821\u9a8c\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\uff0c\u7528\u4e8e\u5b9e\u73b0\u5bf9\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u7ed3\u679c\u7684\u6821\u9a8c setup_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c teardown_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u6237\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c extract \u652f\u6301\u591a\u79cd\u63d0\u53d6\u65b9\u5f0f\uff1a \u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u7ed3\u6784\uff0c\u53ef\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 headers.Content-Type \u3001 content.success \uff1b \u54cd\u5e94\u7ed3\u679c\u4e3a text/html \u7ed3\u6784\uff0c\u53ef\u91c7\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 blog-motto\\\">(.*) \u8be6\u60c5\u53ef\u9605\u8bfb \u300aApiTestEngine\uff0c\u4e0d\u518d\u5c40\u9650\u4e8eAPI\u7684\u6d4b\u8bd5\u300b validate \u652f\u6301\u4e24\u79cd\u683c\u5f0f\uff1a {\"comparator_name\": [check_item, expect_value]} {\"check\": check_item, \"comparator\": comparator_name, \"expect\": expect_value} hooks setup_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e09\u4e2a\u53c2\u6570\uff1a method: \u8bf7\u6c42\u65b9\u6cd5\uff0ce.g. GET, POST, PUT url: \u8bf7\u6c42 URL kwargs: request \u7684\u53c2\u6570\u5b57\u5178 teardown_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u53c2\u6570\uff1a resp_obj: requests.Response \u5b9e\u4f8b \u5173\u4e8e setup_hooks \u548c teardown_hooks \u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u53c2\u8003 \u300ahook \u673a\u5236\u300b \u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7"},{"location":"prepare/testcase-structure/#yaml-json","text":"HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u652f\u6301\u4e24\u79cd\u6587\u4ef6\u683c\u5f0f\uff1aYAML \u548c JSON\u3002 JSON \u548c YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u5b8c\u5168\u7b49\u4ef7\uff0c\u5305\u542b\u7684\u4fe1\u606f\u5185\u5bb9\u4e5f\u5b8c\u5168\u76f8\u540c\u3002 \u5bf9\u4e8e\u65b0\u624b\u6765\u8bf4\uff0c\u63a8\u8350\u4f7f\u7528 JSON \u683c\u5f0f\uff0c\u867d\u7136\u63cf\u8ff0\u5f62\u5f0f\u4e0a\u7a0d\u663e\u7d2f\u8d58\uff0c\u4f46\u662f\u4e0d\u5bb9\u6613\u51fa\u9519\uff08\u5927\u591a\u7f16\u8f91\u5668\u90fd\u5177\u6709 JSON \u683c\u5f0f\u7684\u68c0\u6d4b\u529f\u80fd\uff09\uff1b\u540c\u65f6\uff0cHttpRunner \u4e5f\u5185\u7f6e\u4e86 JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b\u548c\u6837\u5f0f\u7f8e\u5316\u529f\u80fd\uff0c\u8be6\u60c5\u53ef\u67e5\u770b \u300aValidate & Prettify\u300b \u3002 \u5bf9\u4e8e\u719f\u6089 YAML \u683c\u5f0f\u7684\u4eba\u6765\u8bf4\uff0c\u7f16\u5199\u7ef4\u62a4 YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4f1a\u66f4\u7b80\u6d01\uff0c\u4f46\u524d\u63d0\u662f\u8981\u4fdd\u8bc1 YAML \u683c\u5f0f\u6ca1\u6709\u8bed\u6cd5\u9519\u8bef\u3002 \u5bf9\u4e8e\u4e24\u79cd\u683c\u5f0f\u7684\u5c55\u793a\u5dee\u5f02\uff0c\u53ef\u4ee5\u5bf9\u6bd4\u67e5\u770b demo-quickstart-6.json \u548c demo-quickstart-6.yml \u83b7\u53d6\u521d\u6b65\u7684\u5370\u8c61\u3002 \u540e\u9762\u4e3a\u4e86\u66f4\u6e05\u6670\u7684\u63cf\u8ff0\uff0c\u7edf\u4e00\u91c7\u7528 JSON \u683c\u5f0f\u4f5c\u4e3a\u793a\u4f8b\u3002","title":"YAML & JSON"},{"location":"prepare/testcase-structure/#_1","text":"\u5728 HttpRunner \u4e2d\uff0c\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u4e3b\u8981\u57fa\u4e8e\u4e09\u4e2a\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a\u6587\u4ef6\u5939\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08 YAML/JSON \uff09\u6587\u4ef6 \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a YAML/JSON \u6587\u4ef6\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff1a\u5bf9\u5e94 YAML/JSON \u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a test \uff0c\b\u63cf\u8ff0\u5355\u6b21\u63a5\u53e3\u6d4b\u8bd5\u7684\u5168\u90e8\u5185\u5bb9\uff0c\u5305\u62ec\u53d1\u8d77\u63a5\u53e3\u8bf7\u6c42\u3001\u89e3\u6790\u54cd\u5e94\u7ed3\u679c\u3001\u6821\u9a8c\u7ed3\u679c\u7b49 \u5bf9\u4e8e\u5355\u4e2a YAML/JSON \u6587\u4ef6\u6765\u8bf4\uff0c\u6570\u636e\u5b58\u50a8\u7ed3\u6784\u4e3a list of dict \u7684\u5f62\u5f0f\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u4e00\u4e2a\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u3002 \u5177\u4f53\u5730\uff1a config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879 test\uff1a\u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5b58\u5728\u987a\u5e8f\u5173\u7cfb\uff0c\u8fd0\u884c\u65f6\u5c06\u4ece\u524d\u5f80\u540e\u4f9d\u6b21\u8fd0\u884c\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u5bf9\u5e94\u7684 JSON \u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { ... } }, { \"test\" : { ... } }, { \"test\" : { ... } } ]","title":"\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784"},{"location":"prepare/testcase-structure/#context","text":"\u5728\u6d4b\u8bd5\u7528\u4f8b\u5185\u90e8\uff0cHttpRunner \u5212\u5206\u4e86\u4e24\u5c42\u53d8\u91cf\u7a7a\u95f4\u4f5c\u7528\u57df\uff08context\uff09\u3002 config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff1b test\uff1a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f1a\u7ee7\u627f\u6216\u8986\u76d6 config \u4e2d\u5b9a\u4e49\u7684\u5185\u5bb9\uff1b \u82e5\u67d0\u53d8\u91cf\u5728 config \u4e2d\u5b9a\u4e49\u4e86\uff0c\u5728\u67d0 test \u4e2d\u6ca1\u6709\u5b9a\u4e49\uff0c\u5219\u8be5 test \u4f1a\u7ee7\u627f\u8be5\u53d8\u91cf \u82e5\u67d0\u53d8\u91cf\u5728 config \u548c\u67d0 test \u4e2d\u90fd\u5b9a\u4e49\u4e86\uff0c\u5219\u8be5 test \u4e2d\u4f7f\u7528\u81ea\u5df1\u5b9a\u4e49\u7684\u53d8\u91cf\u503c \u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u7684\u53d8\u91cf\u7a7a\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u4e92\u4e0d\u5f71\u54cd\uff1b \u5982\u9700\u5728\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\u4f20\u9012\u53c2\u6570\u503c\uff0c\u5219\u9700\u8981\u4f7f\u7528 extract \u5173\u952e\u5b57\uff0c\u5e76\u4e14\u53ea\u80fd\u4ece\u524d\u5f80\u540e\u4f20\u9012","title":"\u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f5c\u7528\u57df"},{"location":"prepare/testcase-structure/#config","text":"\"config\" : { \"name\" : \"testcase description\" , \"parameters\" : [ { \"user_agent\" : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ]}, { \"app_version\" : \"${P(app_version.csv)}\" }, { \"os_platform\" : \"${get_os_platform()}\" } ], \"variables\" : [ { \"user_agent\" : \"iOS/10.3\" }, { \"device_sn\" : \"${gen_random_string(15)}\" }, { \"os_platform\" : \"ios\" } ], \"request\" : { \"base_url\" : \"http://127.0.0.1:5000\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"$device_sn\" } }, \"output\" : [ \"token\" ] } Key required? format descrption name Yes string \u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6807\u9898 variables No list of dict \u5b9a\u4e49\u7684\u5168\u5c40\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b parameters No list of dict \u5168\u5c40\u53c2\u6570\uff0c\u7528\u4e8e\u5b9e\u73b0\u6570\u636e\u5316\u9a71\u52a8\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b request No dict request \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b\uff1b\u5e38\u7528\u53c2\u6570\u5305\u62ec base_url \u548c headers request Key required? format descrption base_url No string \u6d4b\u8bd5\u7528\u4f8b\u8bf7\u6c42 URL \u7684\u516c\u5171 host\uff0c\u6307\u5b9a\u8be5\u53c2\u6570\u540e\uff0ctest \u4e2d\u7684 url \u53ef\u4ee5\u53ea\u63cf\u8ff0 path \u90e8\u5206 headers No dict request \u4e2d headers \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b output No list \u6574\u4e2a\u7528\u4f8b\u8f93\u51fa\u7684\u53c2\u6570\u5217\u8868\uff0c\u53ef\u8f93\u51fa\u7684\u53c2\u6570\u5305\u62ec\u516c\u5171\u7684 variable \u548c extract \u7684\u53c2\u6570; \u5728 log-level \u4e3a debug \u6a21\u5f0f\u4e0b\uff0c\u4f1a\u5728 terminal \u4e2d\u6253\u5370\u51fa\u53c2\u6570\u5185\u5bb9","title":"config"},{"location":"prepare/testcase-structure/#test","text":"\"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ], \"setup_hooks\" : [], \"teardown_hooks\" : [] } } Key required? format descrption name Yes string \u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0 request Yes dict HTTP \u8bf7\u6c42\u7684\u8be6\u7ec6\u5185\u5bb9\uff1b\u53ef\u7528\u53c2\u6570\u8be6\u89c1 python-requests \u5b98\u65b9\u6587\u6863 variables No list of dict \u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 extract No list \u4ece\u5f53\u524d HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5e76\u4fdd\u5b58\u5230\u53c2\u6570\u53d8\u91cf\u4e2d\uff08\u4f8b\u5982 token \uff09\uff0c\u540e\u7eed\u6d4b\u8bd5\u7528\u4f8b\u53ef\u901a\u8fc7 $token \u7684\u5f62\u5f0f\u8fdb\u884c\u5f15\u7528 validate No list \u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u7684\u7ed3\u679c\u6821\u9a8c\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\uff0c\u7528\u4e8e\u5b9e\u73b0\u5bf9\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u7ed3\u679c\u7684\u6821\u9a8c setup_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c teardown_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u6237\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c extract \u652f\u6301\u591a\u79cd\u63d0\u53d6\u65b9\u5f0f\uff1a \u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u7ed3\u6784\uff0c\u53ef\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 headers.Content-Type \u3001 content.success \uff1b \u54cd\u5e94\u7ed3\u679c\u4e3a text/html \u7ed3\u6784\uff0c\u53ef\u91c7\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 blog-motto\\\">(.*) \u8be6\u60c5\u53ef\u9605\u8bfb \u300aApiTestEngine\uff0c\u4e0d\u518d\u5c40\u9650\u4e8eAPI\u7684\u6d4b\u8bd5\u300b validate \u652f\u6301\u4e24\u79cd\u683c\u5f0f\uff1a {\"comparator_name\": [check_item, expect_value]} {\"check\": check_item, \"comparator\": comparator_name, \"expect\": expect_value} hooks setup_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e09\u4e2a\u53c2\u6570\uff1a method: \u8bf7\u6c42\u65b9\u6cd5\uff0ce.g. GET, POST, PUT url: \u8bf7\u6c42 URL kwargs: request \u7684\u53c2\u6570\u5b57\u5178 teardown_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u53c2\u6570\uff1a resp_obj: requests.Response \u5b9e\u4f8b \u5173\u4e8e setup_hooks \u548c teardown_hooks \u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u53c2\u8003 \u300ahook \u673a\u5236\u300b \u3002","title":"test"},{"location":"prepare/validate-pretty/","text":"HttpRunner \u4ece 1.3.1 \u7248\u672c\u5f00\u59cb\uff0c\u652f\u6301\u5bf9 JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u7684\u5185\u5bb9\u8fdb\u884c\u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b\u548c\u6837\u5f0f\u7f8e\u5316\u529f\u80fd\u3002 JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b \u00b6 \u82e5\u9700\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u7684\u5185\u5bb9\u8fdb\u884c\u6b63\u786e\u6027\u68c0\u6d4b\uff0c\u53ef\u4f7f\u7528 --validate \u53c2\u6570\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json OK \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json Start to validate JSON file: docs/data/demo-quickstart.json OK WARNING Only JSON file format can be validated, skip docs/data/demo-quickstart.yml Start to validate JSON file: docs/data/demo-quickstart-0.json OK \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u6b63\u786e\uff0c\u5219\u6253\u5370 OK\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json Expecting ',' delimiter: line 5 column 13 ( char 82 ) JSON \u683c\u5f0f\u7f8e\u5316 \u00b6 \u4e0e YAML \u683c\u5f0f\u4e0d\u540c\uff0cJSON \u683c\u5f0f\u4e0d\u5f3a\u5236\u8981\u6c42\u7f29\u8fdb\u548c\u6362\u884c\uff0c\u8fd9\u6709\u70b9\u7c7b\u4f3c\u4e8e C \u8bed\u8a00\u548c Python \u8bed\u8a00\u7684\u5dee\u5f02\u3002 \u4f8b\u5982\uff0c demo-quickstart.json \u6587\u4ef6\u4e5f\u53ef\u4ee5\u6539\u5199\u4e3a\u5982\u4e0b\u5f62\u5f0f\u3002 [{ \"config\" : { \"name\" : \"testcase description\" , \"variables\" : [], \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" }}}},{ \"test\" : { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"user_agent\" : \"iOS/10.3\" , \"os_platform\" : \"ios\" , \"app_version\" : \"2.8.6\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 200 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]}]}},{ \"test\" : { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"baNLX1zhFYP11Seb\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 201 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]}]}}] \u867d\u7136\u4e0a\u9762 JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u6267\u884c\uff0c\u4f46\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u53ef\u8bfb\u6027\u592a\u5dee\uff0c\u4e0d\u5229\u4e8e\u9605\u8bfb\u548c\u7ef4\u62a4\u3002 \u9488\u5bf9\u8be5\u9700\u6c42\uff0c\u53ef\u4f7f\u7528 --prettify \u53c2\u6570\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u6837\u5f0f\u7f8e\u5316\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json WARNING Only JSON file format can be prettified, skip: docs/data/demo-quickstart.yml Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json Start to prettify JSON file: docs/data/demo-quickstart-0.json success: docs/data/demo-quickstart-0.pretty.json \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5\u8f6c\u6362\u6210\u529f\uff0c\u5219\u6253\u5370\u7f8e\u5316\u540e\u7684\u6587\u4ef6\u8def\u5f84\uff1b\u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002","title":"Validate & Prettify"},{"location":"prepare/validate-pretty/#json","text":"\u82e5\u9700\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u7684\u5185\u5bb9\u8fdb\u884c\u6b63\u786e\u6027\u68c0\u6d4b\uff0c\u53ef\u4f7f\u7528 --validate \u53c2\u6570\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json OK \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json Start to validate JSON file: docs/data/demo-quickstart.json OK WARNING Only JSON file format can be validated, skip docs/data/demo-quickstart.yml Start to validate JSON file: docs/data/demo-quickstart-0.json OK \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u6b63\u786e\uff0c\u5219\u6253\u5370 OK\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json Expecting ',' delimiter: line 5 column 13 ( char 82 )","title":"JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b"},{"location":"prepare/validate-pretty/#json_1","text":"\u4e0e YAML \u683c\u5f0f\u4e0d\u540c\uff0cJSON \u683c\u5f0f\u4e0d\u5f3a\u5236\u8981\u6c42\u7f29\u8fdb\u548c\u6362\u884c\uff0c\u8fd9\u6709\u70b9\u7c7b\u4f3c\u4e8e C \u8bed\u8a00\u548c Python \u8bed\u8a00\u7684\u5dee\u5f02\u3002 \u4f8b\u5982\uff0c demo-quickstart.json \u6587\u4ef6\u4e5f\u53ef\u4ee5\u6539\u5199\u4e3a\u5982\u4e0b\u5f62\u5f0f\u3002 [{ \"config\" : { \"name\" : \"testcase description\" , \"variables\" : [], \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" }}}},{ \"test\" : { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"user_agent\" : \"iOS/10.3\" , \"os_platform\" : \"ios\" , \"app_version\" : \"2.8.6\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 200 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]}]}},{ \"test\" : { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"baNLX1zhFYP11Seb\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 201 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]}]}}] \u867d\u7136\u4e0a\u9762 JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u6267\u884c\uff0c\u4f46\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u53ef\u8bfb\u6027\u592a\u5dee\uff0c\u4e0d\u5229\u4e8e\u9605\u8bfb\u548c\u7ef4\u62a4\u3002 \u9488\u5bf9\u8be5\u9700\u6c42\uff0c\u53ef\u4f7f\u7528 --prettify \u53c2\u6570\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u6837\u5f0f\u7f8e\u5316\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json WARNING Only JSON file format can be prettified, skip: docs/data/demo-quickstart.yml Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json Start to prettify JSON file: docs/data/demo-quickstart-0.json success: docs/data/demo-quickstart-0.pretty.json \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5\u8f6c\u6362\u6210\u529f\uff0c\u5219\u6253\u5370\u7f8e\u5316\u540e\u7684\u6587\u4ef6\u8def\u5f84\uff1b\u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002","title":"JSON \u683c\u5f0f\u7f8e\u5316"},{"location":"run-tests/cli/","text":"HttpRunner \u5728\u547d\u4ee4\u884c\u4e2d\u542f\u52a8\u6d4b\u8bd5\u65f6\uff0c\u901a\u8fc7\u6307\u5b9a\u53c2\u6570\uff0c\u53ef\u5b9e\u73b0\u4e30\u5bcc\u7684\u6d4b\u8bd5\u7279\u6027\u63a7\u5236\u3002 $ hrun -h usage: hrun [-h] [-V] [--log-level LOG_LEVEL] [--log-file LOG_FILE] [--dot-env-path DOT_ENV_PATH] [--report-template REPORT_TEMPLATE] [--report-dir REPORT_DIR] [--failfast] [--save-tests] [--startproject STARTPROJECT] [--validate [VALIDATE [VALIDATE ...]]] [--prettify [PRETTIFY [PRETTIFY ...]]] [testcase_paths [testcase_paths ...]] One-stop solution for HTTP(S) testing. positional arguments: testcase_paths testcase file path optional arguments: -h, --help show this help message and exit -V, --version show version --log-level LOG_LEVEL Specify logging level, default is INFO. --log-file LOG_FILE Write logs to specified file path. --dot-env-path DOT_ENV_PATH Specify .env file path, which is useful for keeping sensitive data. --report-template REPORT_TEMPLATE specify report template path. --report-dir REPORT_DIR specify report save directory. --failfast Stop the test run on the first error or failure. --save-tests Save loaded tests and parsed tests to JSON file. --startproject STARTPROJECT Specify new project name. --validate [VALIDATE [VALIDATE ...]] Validate JSON testcase format. --prettify [PRETTIFY [PRETTIFY ...]] Prettify JSON testcase format. \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84 \u00b6 \u4f7f\u7528 HttpRunner \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84\u65f6\uff0c\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u3002 \u4f7f\u7528 hrun \u547d\u4ee4\u5916\u52a0\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u8fd0\u884c\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun filepath/testcase.yml \u5c06\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u653e\u7f6e\u5230\u6587\u4ef6\u5939\u4e2d\uff0c\u6307\u5b9a\u6587\u4ef6\u5939\u8def\u5f84\u53ef\u5c06\u6587\u4ef6\u5939\u4e0b\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\u4f5c\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u8fdb\u884c\u8fd0\u884c\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun testcases_folder_path failfast \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u4f1a\u8fd0\u884c\u6307\u5b9a\u7528\u4f8b\u96c6\u4e2d\u7684\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u7edf\u8ba1\u6d4b\u8bd5\u7ed3\u679c\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u4f9d\u8d56\u4e8e\u6267\u884c\u987a\u5e8f\u7684\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u9700\u8981\u5148\u767b\u5f55\u6210\u529f\u624d\u80fd\u6267\u884c\u540e\u7eed\u63a5\u53e3\u8bf7\u6c42\u7684\u573a\u666f\uff0c\u5f53\u524d\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\u6267\u884c\u5931\u8d25\u540e\uff0c\u540e\u7eed\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u90fd\u5fc5\u5c06\u5931\u8d25\uff0c\u56e0\u6b64\u6ca1\u6709\u7ee7\u7eed\u6267\u884c\u7684\u5fc5\u8981\u4e86\u3002 \u82e5\u5e0c\u671b\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u8fc7\u7a0b\u4e2d\uff0c\u9047\u5230\u5931\u8d25\u65f6\u4e0d\u518d\u7ee7\u7eed\u8fd0\u884c\u540e\u7eed\u7528\u4f8b\uff0c\u5219\u53ef\u901a\u8fc7\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --failfast \u5b9e\u73b0\u3002 $ hrun filepath/testcase.yml --failfast \u65e5\u5fd7\u7ea7\u522b \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u8fd0\u884c\u65f6\u7684\u65e5\u5fd7\u7ea7\u522b\u4e3a INFO \uff0c\u53ea\u4f1a\u5305\u542b\u6700\u57fa\u672c\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u7528\u4f8b\u540d\u79f0\u3001\u8bf7\u6c42\u7684URL\u548cMethod\u3001\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u3001\u8017\u65f6\u548c\u5185\u5bb9\u5927\u5c0f\u3002 $ hrun docs/data/demo-quickstart-6.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.08 ms, response_length: 46 bytes . /api/users/1548560655759 INFO POST http://127.0.0.1:5000/api/users/1548560655759 INFO status_code: 201, response_time(ms): 2.89 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560655.html \u82e5\u9700\u8981\u67e5\u770b\u5230\u66f4\u8be6\u5c3d\u7684\u4fe1\u606f\uff0c\u4f8b\u5982\u8bf7\u6c42\u7684\u53c2\u6570\u548c\u54cd\u5e94\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u53ef\u4ee5\u5c06\u65e5\u5fd7\u7ea7\u522b\u8bbe\u7f6e\u4e3a DEBUG \uff0c\u5373\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --log-level debug \u3002 $ hrun docs/data/demo-quickstart-6.json --log-level debug INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/get-token > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/get-token' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json', 'Content-Length': '52'} body : b'{\"sign\": \"2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/get-token' status_code : 200 reason : 'OK' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'token': 'o6uakmubLrCbpRRS'} INFO status_code: 200, response_time(ms): 9.28 ms, response_length: 46 bytes DEBUG start to extract from response object. DEBUG extract: content.token => o6uakmubLrCbpRRS DEBUG start to validate. DEBUG extract: status_code => 200 DEBUG validate: status_code equals 200(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass . /api/users/1548560716736 INFO POST http://127.0.0.1:5000/api/users/1548560716736 DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/users/1548560716736 > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/users/1548560716736' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json', 'Content-Length': '39'} body : b'{\"name\": \"user1\", \"password\": \"123456\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/users/1548560716736' status_code : 201 reason : 'CREATED' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '54', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'msg': 'user created successfully.'} INFO status_code: 201, response_time(ms): 2.77 ms, response_length: 54 bytes DEBUG start to validate. DEBUG extract: status_code => 201 DEBUG validate: status_code equals 201(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass DEBUG extract: content.msg => user created successfully. DEBUG validate: content.msg equals user created successfully.(str) ==> pass . ---------------------------------------------------------------------- Ran 2 tests in 0.022s OK DEBUG No html report template specified, use default. INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560716.html \u4fdd\u5b58\u8be6\u7ec6\u8fc7\u7a0b\u6570\u636e \u00b6 \u4e3a\u4e86\u65b9\u4fbf\u5b9a\u4f4d\u95ee\u9898\uff0c\u8fd0\u884c\u6d4b\u8bd5\u65f6\u53ef\u6307\u5b9a --save-tests \u53c2\u6570\uff0c\u5373\u53ef\u5c06\u8fd0\u884c\u8fc7\u7a0b\u7684\u4e2d\u95f4\u6570\u636e\u4fdd\u5b58\u4e3a\u65e5\u5fd7\u6587\u4ef6\u3002 $ hrun docs/data/demo-quickstart-6.json --save-tests dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.loaded.json dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.parsed.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 11.42 ms, response_length: 46 bytes . /api/users/1548560768589 INFO POST http://127.0.0.1:5000/api/users/1548560768589 INFO status_code: 201, response_time(ms): 2.8 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.028s OK dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.summary.json INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560768.html \u65e5\u5fd7\u6587\u4ef6\u5c06\u4fdd\u5b58\u5728\u9879\u76ee\u6839\u76ee\u5f55\u7684 logs \u6587\u4ef6\u5939\u4e2d\uff0c\u751f\u6210\u7684\u6587\u4ef6\u6709\u5982\u4e0b\u4e09\u4e2a\uff08XXX\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u540d\u79f0\uff09\uff1a XXX.loaded.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u52a0\u8f7d\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u52a0\u8f7d\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff08YAML/JSON\uff09\u3001debugtalk.py\u3001.env \u7b49\u6240\u6709\u9879\u76ee\u6587\u4ef6\uff0c\u4f8b\u5982 demo-quickstart-6.loaded.json XXX.parsed.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u89e3\u6790\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u89e3\u6790\u5185\u5bb9\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u5f15\u7528\uff08API/testcase\uff09\u3001\u53d8\u91cf\u8ba1\u7b97\u548c\u66ff\u6362\u3001base_url \u62fc\u63a5\u7b49\uff0c\u4f8b\u5982 demo-quickstart-6.parsed.json XXX.summary.json \uff1a\u6d4b\u8bd5\u62a5\u544a\u751f\u6210\u524d\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u4f8b\u5982 demo-quickstart-6.summary.json","title":"\u8fd0\u884c\u6d4b\u8bd5(CLI)"},{"location":"run-tests/cli/#_1","text":"\u4f7f\u7528 HttpRunner \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84\u65f6\uff0c\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u3002 \u4f7f\u7528 hrun \u547d\u4ee4\u5916\u52a0\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u8fd0\u884c\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun filepath/testcase.yml \u5c06\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u653e\u7f6e\u5230\u6587\u4ef6\u5939\u4e2d\uff0c\u6307\u5b9a\u6587\u4ef6\u5939\u8def\u5f84\u53ef\u5c06\u6587\u4ef6\u5939\u4e0b\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\u4f5c\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u8fdb\u884c\u8fd0\u884c\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun testcases_folder_path","title":"\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84"},{"location":"run-tests/cli/#failfast","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u4f1a\u8fd0\u884c\u6307\u5b9a\u7528\u4f8b\u96c6\u4e2d\u7684\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u7edf\u8ba1\u6d4b\u8bd5\u7ed3\u679c\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u4f9d\u8d56\u4e8e\u6267\u884c\u987a\u5e8f\u7684\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u9700\u8981\u5148\u767b\u5f55\u6210\u529f\u624d\u80fd\u6267\u884c\u540e\u7eed\u63a5\u53e3\u8bf7\u6c42\u7684\u573a\u666f\uff0c\u5f53\u524d\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\u6267\u884c\u5931\u8d25\u540e\uff0c\u540e\u7eed\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u90fd\u5fc5\u5c06\u5931\u8d25\uff0c\u56e0\u6b64\u6ca1\u6709\u7ee7\u7eed\u6267\u884c\u7684\u5fc5\u8981\u4e86\u3002 \u82e5\u5e0c\u671b\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u8fc7\u7a0b\u4e2d\uff0c\u9047\u5230\u5931\u8d25\u65f6\u4e0d\u518d\u7ee7\u7eed\u8fd0\u884c\u540e\u7eed\u7528\u4f8b\uff0c\u5219\u53ef\u901a\u8fc7\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --failfast \u5b9e\u73b0\u3002 $ hrun filepath/testcase.yml --failfast","title":"failfast"},{"location":"run-tests/cli/#_2","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u8fd0\u884c\u65f6\u7684\u65e5\u5fd7\u7ea7\u522b\u4e3a INFO \uff0c\u53ea\u4f1a\u5305\u542b\u6700\u57fa\u672c\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u7528\u4f8b\u540d\u79f0\u3001\u8bf7\u6c42\u7684URL\u548cMethod\u3001\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u3001\u8017\u65f6\u548c\u5185\u5bb9\u5927\u5c0f\u3002 $ hrun docs/data/demo-quickstart-6.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.08 ms, response_length: 46 bytes . /api/users/1548560655759 INFO POST http://127.0.0.1:5000/api/users/1548560655759 INFO status_code: 201, response_time(ms): 2.89 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560655.html \u82e5\u9700\u8981\u67e5\u770b\u5230\u66f4\u8be6\u5c3d\u7684\u4fe1\u606f\uff0c\u4f8b\u5982\u8bf7\u6c42\u7684\u53c2\u6570\u548c\u54cd\u5e94\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u53ef\u4ee5\u5c06\u65e5\u5fd7\u7ea7\u522b\u8bbe\u7f6e\u4e3a DEBUG \uff0c\u5373\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --log-level debug \u3002 $ hrun docs/data/demo-quickstart-6.json --log-level debug INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/get-token > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/get-token' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json', 'Content-Length': '52'} body : b'{\"sign\": \"2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/get-token' status_code : 200 reason : 'OK' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'token': 'o6uakmubLrCbpRRS'} INFO status_code: 200, response_time(ms): 9.28 ms, response_length: 46 bytes DEBUG start to extract from response object. DEBUG extract: content.token => o6uakmubLrCbpRRS DEBUG start to validate. DEBUG extract: status_code => 200 DEBUG validate: status_code equals 200(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass . /api/users/1548560716736 INFO POST http://127.0.0.1:5000/api/users/1548560716736 DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/users/1548560716736 > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/users/1548560716736' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json', 'Content-Length': '39'} body : b'{\"name\": \"user1\", \"password\": \"123456\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/users/1548560716736' status_code : 201 reason : 'CREATED' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '54', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'msg': 'user created successfully.'} INFO status_code: 201, response_time(ms): 2.77 ms, response_length: 54 bytes DEBUG start to validate. DEBUG extract: status_code => 201 DEBUG validate: status_code equals 201(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass DEBUG extract: content.msg => user created successfully. DEBUG validate: content.msg equals user created successfully.(str) ==> pass . ---------------------------------------------------------------------- Ran 2 tests in 0.022s OK DEBUG No html report template specified, use default. INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560716.html","title":"\u65e5\u5fd7\u7ea7\u522b"},{"location":"run-tests/cli/#_3","text":"\u4e3a\u4e86\u65b9\u4fbf\u5b9a\u4f4d\u95ee\u9898\uff0c\u8fd0\u884c\u6d4b\u8bd5\u65f6\u53ef\u6307\u5b9a --save-tests \u53c2\u6570\uff0c\u5373\u53ef\u5c06\u8fd0\u884c\u8fc7\u7a0b\u7684\u4e2d\u95f4\u6570\u636e\u4fdd\u5b58\u4e3a\u65e5\u5fd7\u6587\u4ef6\u3002 $ hrun docs/data/demo-quickstart-6.json --save-tests dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.loaded.json dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.parsed.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 11.42 ms, response_length: 46 bytes . /api/users/1548560768589 INFO POST http://127.0.0.1:5000/api/users/1548560768589 INFO status_code: 201, response_time(ms): 2.8 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.028s OK dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.summary.json INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560768.html \u65e5\u5fd7\u6587\u4ef6\u5c06\u4fdd\u5b58\u5728\u9879\u76ee\u6839\u76ee\u5f55\u7684 logs \u6587\u4ef6\u5939\u4e2d\uff0c\u751f\u6210\u7684\u6587\u4ef6\u6709\u5982\u4e0b\u4e09\u4e2a\uff08XXX\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u540d\u79f0\uff09\uff1a XXX.loaded.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u52a0\u8f7d\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u52a0\u8f7d\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff08YAML/JSON\uff09\u3001debugtalk.py\u3001.env \u7b49\u6240\u6709\u9879\u76ee\u6587\u4ef6\uff0c\u4f8b\u5982 demo-quickstart-6.loaded.json XXX.parsed.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u89e3\u6790\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u89e3\u6790\u5185\u5bb9\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u5f15\u7528\uff08API/testcase\uff09\u3001\u53d8\u91cf\u8ba1\u7b97\u548c\u66ff\u6362\u3001base_url \u62fc\u63a5\u7b49\uff0c\u4f8b\u5982 demo-quickstart-6.parsed.json XXX.summary.json \uff1a\u6d4b\u8bd5\u62a5\u544a\u751f\u6210\u524d\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u4f8b\u5982 demo-quickstart-6.summary.json","title":"\u4fdd\u5b58\u8be6\u7ec6\u8fc7\u7a0b\u6570\u636e"},{"location":"run-tests/load-test/","text":"HttpRunner \u901a\u8fc7\u590d\u7528 Locust \uff0c\u53ef\u4ee5\u5728\u65e0\u9700\u5bf9 YAML/JSON \u8fdb\u884c\u4efb\u4f55\u4fee\u6539\u7684\u60c5\u51b5\u4e0b\uff0c\u76f4\u63a5\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5\u3002 \u539f\u7406\u56fe \u00b6 \u5b89\u88c5\u4f9d\u8d56\u5305 \u00b6 \u5b89\u88c5\u5b8c\u6210 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e locusts \u547d\u4ee4\uff0c\u4f46\u4e0d\u4f1a\u540c\u65f6\u5b89\u88c5 Locust\u3002 \u5728\u7cfb\u7edf\u4e2d\u672a\u5b89\u88c5 Locust \u7684\u60c5\u51b5\u4e0b\uff0c\u8fd0\u884c locusts \u547d\u4ee4\u65f6\u4f1a\u51fa\u73b0\u5982\u4e0b\u63d0\u793a\u3002 $ locusts -V WARNING Locust is not installed, install first and try again. install command: pip install locustio Locust \u7684\u5b89\u88c5\u65b9\u5f0f\u5982\u4e0b\uff1a $ pip install locustio \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u6267\u884c locusts -V \u53ef\u67e5\u770b\u5230 Locust \u7684\u7248\u672c\u53f7\u3002 $ locusts -V [2017-08-26 23:45:42,246] bogon/INFO/stdout: Locust 0.8a2 [2017-08-26 23:45:42,246] bogon/INFO/stdout: \u6267\u884c locusts -h \uff0c\u53ef\u67e5\u770b\u5230\u4f7f\u7528\u5e2e\u52a9\u6587\u6863\u3002 $ locusts -h Usage: locust [options] [LocustClass [LocustClass2 ... ]] Options: -h, --help show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33 --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE Store current request stats to files in CSV format. --master Set locust to run in distributed mode with this process as master --slave Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats --no-reset-stats Do not reset statistics once hatching has been completed -l, --list Show list of possible locust classes and exit --show-task-ratio print table of the locust classes' task execution ratio --show-task-ratio-json print json data of the locust classes' task execution ratio -V, --version show program's version number and exit \u53ef\u4ee5\u770b\u51fa\uff0c loucsts \u547d\u4ee4\u4e0e locust \u547d\u4ee4\u7684\u7528\u6cd5\u57fa\u672c\u76f8\u540c\u3002 \u76f8\u6bd4\u4e8e locust \u547d\u4ee4\uff0c loucsts \u547d\u4ee4\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u4e24\u9879\u5dee\u5f02\u3002 \u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5 \u00b6 \u5728 -f \u53c2\u6570\u540e\u9762\uff0c loucsts \u547d\u4ee4\u4e0d\u4ec5\u53ef\u4ee5\u6307\u5b9a Locust \u652f\u6301\u7684 Python \u6587\u4ef6\uff0c\u540c\u65f6\u53ef\u4ee5\u76f4\u63a5\u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002\u5728\u5177\u4f53\u5b9e\u73b0\u4e0a\uff0c\u5f53 -f \u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u65f6\uff0c\u4f1a\u5148\u5c06\u5176\u8f6c\u6362\u4e3a Python \u683c\u5f0f\u7684 locustfile\uff0c\u7136\u540e\u518d\u5c06 locustfile.py \u4f20\u7ed9 locust \u547d\u4ee4\u3002 $ locusts -f examples/first-testcase.yml [ 2017 -08-18 17 :20:43,915 ] Leos-MacBook-Air.local/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-18 17 :20:43,918 ] Leos-MacBook-Air.local/INFO/locust.main: Starting Locust 0 .8a2 \u6267\u884c\u4e0a\u8ff0\u547d\u4ee4\u540e\uff0c\u5373\u5b8c\u6210\u4e86 Locust \u670d\u52a1\u7684\u542f\u52a8\uff0c\u540e\u7eed\u5c31\u53ef\u4ee5\u5728 Locust \u7684 Web \u7ba1\u7406\u754c\u9762\u4e2d\u8fdb\u884c\u64cd\u4f5c\u4e86\uff0c\u4f7f\u7528\u65b9\u5f0f\u4e0e Locust \u5b8c\u5168\u76f8\u540c\u3002 \u591a\u8fdb\u7a0b\u8fd0\u884c\u6a21\u5f0f \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728 Locust \u4e2d\u5982\u9700\u4f7f\u7528 master-slave \u6a21\u5f0f\u542f\u52a8\u591a\u4e2a\u8fdb\u7a0b\uff08\u4f7f\u7528\u591a\u6838\u5904\u7406\u5668\u7684\u80fd\u529b\uff09\uff0c\u53ea\u80fd\u5148\u542f\u52a8 master\uff0c\u7136\u540e\u518d\u9010\u4e00\u542f\u52a8\u82e5\u5e72\u4e2a slave\u3002 $ locust -f locustfile.py --master $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & \u5728 HttpRunner \u4e2d\uff0c\u65b0\u589e\u5b9e\u73b0 --processes \u53c2\u6570\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u542f\u52a8 1 \u4e2a master \u548c\u591a\u4e2a salve\u3002\u82e5\u5728 --processes \u53c2\u6570\u540e\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u7684\u6570\u503c\uff0c\u5219\u542f\u52a8\u7684 slave \u4e2a\u6570\u4e0e\u673a\u5668\u7684 CPU \u6838\u6570\u76f8\u540c\u3002 $ locusts -f examples/first-testcase.yml --processes 4 [ 2017 -08-26 23 :51:47,071 ] bogon/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-26 23 :51:47,075 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,078 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,080 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,083 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.runners: Client 'bogon_656e0af8e968a8533d379dd252422ad3' reported as ready. Currently 1 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_09f73850252ee4ec739ed77d3c4c6dba' reported as ready. Currently 2 clients ready to swarm. [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_869f7ed671b1a9952b56610f01e2006f' reported as ready. Currently 3 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_80a804cda36b80fac17b57fd2d5e7cdb' reported as ready. Currently 4 clients ready to swarm. Enjoy!","title":"\u6027\u80fd\u6d4b\u8bd5"},{"location":"run-tests/load-test/#_1","text":"","title":"\u539f\u7406\u56fe"},{"location":"run-tests/load-test/#_2","text":"\u5b89\u88c5\u5b8c\u6210 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e locusts \u547d\u4ee4\uff0c\u4f46\u4e0d\u4f1a\u540c\u65f6\u5b89\u88c5 Locust\u3002 \u5728\u7cfb\u7edf\u4e2d\u672a\u5b89\u88c5 Locust \u7684\u60c5\u51b5\u4e0b\uff0c\u8fd0\u884c locusts \u547d\u4ee4\u65f6\u4f1a\u51fa\u73b0\u5982\u4e0b\u63d0\u793a\u3002 $ locusts -V WARNING Locust is not installed, install first and try again. install command: pip install locustio Locust \u7684\u5b89\u88c5\u65b9\u5f0f\u5982\u4e0b\uff1a $ pip install locustio \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u6267\u884c locusts -V \u53ef\u67e5\u770b\u5230 Locust \u7684\u7248\u672c\u53f7\u3002 $ locusts -V [2017-08-26 23:45:42,246] bogon/INFO/stdout: Locust 0.8a2 [2017-08-26 23:45:42,246] bogon/INFO/stdout: \u6267\u884c locusts -h \uff0c\u53ef\u67e5\u770b\u5230\u4f7f\u7528\u5e2e\u52a9\u6587\u6863\u3002 $ locusts -h Usage: locust [options] [LocustClass [LocustClass2 ... ]] Options: -h, --help show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33 --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE Store current request stats to files in CSV format. --master Set locust to run in distributed mode with this process as master --slave Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats --no-reset-stats Do not reset statistics once hatching has been completed -l, --list Show list of possible locust classes and exit --show-task-ratio print table of the locust classes' task execution ratio --show-task-ratio-json print json data of the locust classes' task execution ratio -V, --version show program's version number and exit \u53ef\u4ee5\u770b\u51fa\uff0c loucsts \u547d\u4ee4\u4e0e locust \u547d\u4ee4\u7684\u7528\u6cd5\u57fa\u672c\u76f8\u540c\u3002 \u76f8\u6bd4\u4e8e locust \u547d\u4ee4\uff0c loucsts \u547d\u4ee4\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u4e24\u9879\u5dee\u5f02\u3002","title":"\u5b89\u88c5\u4f9d\u8d56\u5305"},{"location":"run-tests/load-test/#_3","text":"\u5728 -f \u53c2\u6570\u540e\u9762\uff0c loucsts \u547d\u4ee4\u4e0d\u4ec5\u53ef\u4ee5\u6307\u5b9a Locust \u652f\u6301\u7684 Python \u6587\u4ef6\uff0c\u540c\u65f6\u53ef\u4ee5\u76f4\u63a5\u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002\u5728\u5177\u4f53\u5b9e\u73b0\u4e0a\uff0c\u5f53 -f \u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u65f6\uff0c\u4f1a\u5148\u5c06\u5176\u8f6c\u6362\u4e3a Python \u683c\u5f0f\u7684 locustfile\uff0c\u7136\u540e\u518d\u5c06 locustfile.py \u4f20\u7ed9 locust \u547d\u4ee4\u3002 $ locusts -f examples/first-testcase.yml [ 2017 -08-18 17 :20:43,915 ] Leos-MacBook-Air.local/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-18 17 :20:43,918 ] Leos-MacBook-Air.local/INFO/locust.main: Starting Locust 0 .8a2 \u6267\u884c\u4e0a\u8ff0\u547d\u4ee4\u540e\uff0c\u5373\u5b8c\u6210\u4e86 Locust \u670d\u52a1\u7684\u542f\u52a8\uff0c\u540e\u7eed\u5c31\u53ef\u4ee5\u5728 Locust \u7684 Web \u7ba1\u7406\u754c\u9762\u4e2d\u8fdb\u884c\u64cd\u4f5c\u4e86\uff0c\u4f7f\u7528\u65b9\u5f0f\u4e0e Locust \u5b8c\u5168\u76f8\u540c\u3002","title":"\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5"},{"location":"run-tests/load-test/#_4","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728 Locust \u4e2d\u5982\u9700\u4f7f\u7528 master-slave \u6a21\u5f0f\u542f\u52a8\u591a\u4e2a\u8fdb\u7a0b\uff08\u4f7f\u7528\u591a\u6838\u5904\u7406\u5668\u7684\u80fd\u529b\uff09\uff0c\u53ea\u80fd\u5148\u542f\u52a8 master\uff0c\u7136\u540e\u518d\u9010\u4e00\u542f\u52a8\u82e5\u5e72\u4e2a slave\u3002 $ locust -f locustfile.py --master $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & \u5728 HttpRunner \u4e2d\uff0c\u65b0\u589e\u5b9e\u73b0 --processes \u53c2\u6570\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u542f\u52a8 1 \u4e2a master \u548c\u591a\u4e2a salve\u3002\u82e5\u5728 --processes \u53c2\u6570\u540e\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u7684\u6570\u503c\uff0c\u5219\u542f\u52a8\u7684 slave \u4e2a\u6570\u4e0e\u673a\u5668\u7684 CPU \u6838\u6570\u76f8\u540c\u3002 $ locusts -f examples/first-testcase.yml --processes 4 [ 2017 -08-26 23 :51:47,071 ] bogon/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-26 23 :51:47,075 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,078 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,080 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,083 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.runners: Client 'bogon_656e0af8e968a8533d379dd252422ad3' reported as ready. Currently 1 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_09f73850252ee4ec739ed77d3c4c6dba' reported as ready. Currently 2 clients ready to swarm. [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_869f7ed671b1a9952b56610f01e2006f' reported as ready. Currently 3 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_80a804cda36b80fac17b57fd2d5e7cdb' reported as ready. Currently 4 clients ready to swarm. Enjoy!","title":"\u591a\u8fdb\u7a0b\u8fd0\u884c\u6a21\u5f0f"},{"location":"run-tests/report/","text":"\u4f7f\u7528 HttpRunner \u6267\u884c\u5b8c\u81ea\u52a8\u5316\u6d4b\u8bd5\u540e\uff0c\u4f1a\u5728\u5f53\u524d\u8def\u5f84\u7684 reports \u76ee\u5f55\u4e0b\u751f\u6210\u4e00\u4efd HTML \u683c\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\u3002 \u9ed8\u8ba4\u60c5\u51b5 \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u5f00\u59cb\u7684\u65f6\u95f4\u6233\u3002 $ hrun docs/data/demo-quickstart-6.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200 , response_time ( ms ) : 10 .05 ms, response_length: 46 bytes . /api/users/1548561170497 INFO POST http://127.0.0.1:5000/api/users/1548561170497 INFO status_code: 201 , response_time ( ms ) : 2 .88 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0 .034s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548561170.html \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002 \u9ed8\u8ba4\u62a5\u544a\u6837\u5f0f \u00b6 \u5728 HttpRunner \u4e2d\u81ea\u5e26\u4e86\u4e00\u4e2a Jinja2 \u683c\u5f0f\u7684\u62a5\u544a\u6a21\u7248\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u62a5\u544a\u6837\u5f0f\u5747\u57fa\u4e8e\u8be5\u6a21\u7248\uff08 httprunner/templates/default_report_template.html \uff09\u3002 \u6d4b\u8bd5\u62a5\u544a\u5f62\u5f0f\u5982\u4e0b\uff1a \u5728 Summary \u4e2d\uff0c\u4f1a\u7f57\u5217\u672c\u6b21\u6d4b\u8bd5\u7684\u6574\u4f53\u4fe1\u606f\uff0c\u5305\u62ec\u6d4b\u8bd5\u5f00\u59cb\u65f6\u95f4\u3001\u603b\u8fd0\u884c\u65f6\u957f\u3001\u8fd0\u884c\u7684Python\u7248\u672c\u548c\u7cfb\u7edf\u73af\u5883\u3001\u8fd0\u884c\u7ed3\u679c\u7edf\u8ba1\u6570\u636e\u3002 \u5728 Details \u4e2d\uff0c\u4f1a\u8be6\u7ec6\u5c55\u793a\u6bcf\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u7ed3\u679c\u3002 \u70b9\u51fb\u6d4b\u8bd5\u7528\u4f8b\u5bf9\u5e94\u7684 log \u6309\u94ae\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u8be5\u7528\u4f8b\u6267\u884c\u7684\u8be6\u7ec6\u6570\u636e\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 headers \u548c body\u3001\u54cd\u5e94\u7684 headers \u548c body\u3001\u6821\u9a8c\u7ed3\u679c\u3001\u54cd\u5e94\u3001\u54cd\u5e94\u8017\u65f6\uff08elapsed\uff09\u7b49\u4fe1\u606f\u3002 \u82e5\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u4e0d\u6210\u529f\uff08failed/error/skipped\uff09\uff0c\u5219\u5728\u8be5\u6d4b\u8bd5\u7528\u4f8b\u7684 detail \u4e2d\u4f1a\u51fa\u73b0 traceback \u6309\u94ae\uff0c\u70b9\u51fb\u8be5\u6309\u94ae\u540e\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u5931\u8d25\u7684\u5806\u6808\u65e5\u5fd7\uff0c\u6216\u8005 skipped \u7684\u539f\u56e0\u3002 \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002 \u81ea\u5b9a\u4e49 \u00b6 \u9664\u4e86\u9ed8\u8ba4\u7684\u62a5\u544a\u6837\u5f0f\uff0cHttpRunner \u8fd8\u652f\u6301\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u62a5\u544a\u6a21\u677f\u3002 \u7f16\u5199\u81ea\u5b9a\u4e49\u6a21\u677f\uff08Jinja2\u683c\u5f0f\uff09 \u00b6 \u81ea\u5b9a\u4e49\u6a21\u677f\u9700\u8981\u91c7\u7528 Jinja2 \u7684\u683c\u5f0f\uff0c\u5176\u4e2d\u53ef\u4ee5\u4f7f\u7528\u7684\u6570\u636e\u53ef\u53c2\u8003 \u6570\u636e\u7ed3\u6784\u793a\u4f8b \u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u81ea\u5b9a\u4e49\u6a21\u677f\u4e2d\u5c55\u793a\u6d4b\u8bd5\u7ed3\u679c\u7684\u7edf\u8ba1\u6570\u636e\uff0c\u5c31\u53ef\u4ee5\u91c7\u7528\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u63cf\u8ff0\uff1a < tr > < th > TOTAL th > < th > SUCCESS th > < th > FAILED th > < th > ERROR th > < th > SKIPPED th > tr > < tr > < td > {{stat.testsRun}} td > < td > {{stat.successes}} td > < td > {{stat.failures}} td > < td > {{stat.errors}} td > < td > {{stat.skipped}} td > tr > \u5728\u81ea\u5b9a\u4e49\u62a5\u544a\u6a21\u677f\u65f6\uff0c\u53ef\u4ee5\u53c2\u8003 HttpRunner \u7684 \u9ed8\u8ba4\u62a5\u544a\u6a21\u677f \uff0c\u8981\u5b9e\u73b0\u66f4\u590d\u6742\u7684\u6a21\u7248\u529f\u80fd\uff0c\u53ef\u53c2\u8003 Jinja2 \u7684\u4f7f\u7528\u6587\u6863\u3002 \u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u677f \u00b6 \u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u7248\u65f6\uff0c\u9700\u8981\u901a\u8fc7 --report-template \u6307\u5b9a\u62a5\u544a\u6a21\u677f\u7684\u8def\u5f84\uff0c\u7136\u540e\u6d4b\u8bd5\u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u5c31\u4f1a\u91c7\u7528\u81ea\u5b9a\u4e49\u7684\u6a21\u677f\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u3002 $ hrun docs/data/demo-quickstart-2.yml --report-template /path/to/custom_report_template ... \u540c\u4e0a\uff0c\u7701\u7565 INFO render with html report template: /path/to/custom_report_template INFO Start to render Html report ... INFO Generated Html report: reports/1532078874.html \u6307\u5b9a\u62a5\u544a\u751f\u6210\u8def\u5f84 \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\u3002\u5982\u9700\u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u8def\u5f84\uff0c\u53ef\u4ee5\u4f7f\u7528 --report-dir \u53c2\u6570\u3002 $ hrun docs/data/demo-quickstart-2.yml --dirreport-name /other/path/ ... \u540c\u4e0a\uff0c\u7701\u7565 INFO Start to render Html report ... INFO Generated Html report: /other/path/1532078874.html","title":"\u6d4b\u8bd5\u62a5\u544a"},{"location":"run-tests/report/#_1","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u5f00\u59cb\u7684\u65f6\u95f4\u6233\u3002 $ hrun docs/data/demo-quickstart-6.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200 , response_time ( ms ) : 10 .05 ms, response_length: 46 bytes . /api/users/1548561170497 INFO POST http://127.0.0.1:5000/api/users/1548561170497 INFO status_code: 201 , response_time ( ms ) : 2 .88 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0 .034s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548561170.html \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002","title":"\u9ed8\u8ba4\u60c5\u51b5"},{"location":"run-tests/report/#_2","text":"\u5728 HttpRunner \u4e2d\u81ea\u5e26\u4e86\u4e00\u4e2a Jinja2 \u683c\u5f0f\u7684\u62a5\u544a\u6a21\u7248\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u62a5\u544a\u6837\u5f0f\u5747\u57fa\u4e8e\u8be5\u6a21\u7248\uff08 httprunner/templates/default_report_template.html \uff09\u3002 \u6d4b\u8bd5\u62a5\u544a\u5f62\u5f0f\u5982\u4e0b\uff1a \u5728 Summary \u4e2d\uff0c\u4f1a\u7f57\u5217\u672c\u6b21\u6d4b\u8bd5\u7684\u6574\u4f53\u4fe1\u606f\uff0c\u5305\u62ec\u6d4b\u8bd5\u5f00\u59cb\u65f6\u95f4\u3001\u603b\u8fd0\u884c\u65f6\u957f\u3001\u8fd0\u884c\u7684Python\u7248\u672c\u548c\u7cfb\u7edf\u73af\u5883\u3001\u8fd0\u884c\u7ed3\u679c\u7edf\u8ba1\u6570\u636e\u3002 \u5728 Details \u4e2d\uff0c\u4f1a\u8be6\u7ec6\u5c55\u793a\u6bcf\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u7ed3\u679c\u3002 \u70b9\u51fb\u6d4b\u8bd5\u7528\u4f8b\u5bf9\u5e94\u7684 log \u6309\u94ae\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u8be5\u7528\u4f8b\u6267\u884c\u7684\u8be6\u7ec6\u6570\u636e\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 headers \u548c body\u3001\u54cd\u5e94\u7684 headers \u548c body\u3001\u6821\u9a8c\u7ed3\u679c\u3001\u54cd\u5e94\u3001\u54cd\u5e94\u8017\u65f6\uff08elapsed\uff09\u7b49\u4fe1\u606f\u3002 \u82e5\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u4e0d\u6210\u529f\uff08failed/error/skipped\uff09\uff0c\u5219\u5728\u8be5\u6d4b\u8bd5\u7528\u4f8b\u7684 detail \u4e2d\u4f1a\u51fa\u73b0 traceback \u6309\u94ae\uff0c\u70b9\u51fb\u8be5\u6309\u94ae\u540e\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u5931\u8d25\u7684\u5806\u6808\u65e5\u5fd7\uff0c\u6216\u8005 skipped \u7684\u539f\u56e0\u3002 \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002","title":"\u9ed8\u8ba4\u62a5\u544a\u6837\u5f0f"},{"location":"run-tests/report/#_3","text":"\u9664\u4e86\u9ed8\u8ba4\u7684\u62a5\u544a\u6837\u5f0f\uff0cHttpRunner \u8fd8\u652f\u6301\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u62a5\u544a\u6a21\u677f\u3002","title":"\u81ea\u5b9a\u4e49"},{"location":"run-tests/report/#jinja2","text":"\u81ea\u5b9a\u4e49\u6a21\u677f\u9700\u8981\u91c7\u7528 Jinja2 \u7684\u683c\u5f0f\uff0c\u5176\u4e2d\u53ef\u4ee5\u4f7f\u7528\u7684\u6570\u636e\u53ef\u53c2\u8003 \u6570\u636e\u7ed3\u6784\u793a\u4f8b \u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u81ea\u5b9a\u4e49\u6a21\u677f\u4e2d\u5c55\u793a\u6d4b\u8bd5\u7ed3\u679c\u7684\u7edf\u8ba1\u6570\u636e\uff0c\u5c31\u53ef\u4ee5\u91c7\u7528\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u63cf\u8ff0\uff1a < tr > < th > TOTAL th > < th > SUCCESS th > < th > FAILED th > < th > ERROR th > < th > SKIPPED th > tr > < tr > < td > {{stat.testsRun}} td > < td > {{stat.successes}} td > < td > {{stat.failures}} td > < td > {{stat.errors}} td > < td > {{stat.skipped}} td > tr > \u5728\u81ea\u5b9a\u4e49\u62a5\u544a\u6a21\u677f\u65f6\uff0c\u53ef\u4ee5\u53c2\u8003 HttpRunner \u7684 \u9ed8\u8ba4\u62a5\u544a\u6a21\u677f \uff0c\u8981\u5b9e\u73b0\u66f4\u590d\u6742\u7684\u6a21\u7248\u529f\u80fd\uff0c\u53ef\u53c2\u8003 Jinja2 \u7684\u4f7f\u7528\u6587\u6863\u3002","title":"\u7f16\u5199\u81ea\u5b9a\u4e49\u6a21\u677f\uff08Jinja2\u683c\u5f0f\uff09"},{"location":"run-tests/report/#_4","text":"\u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u7248\u65f6\uff0c\u9700\u8981\u901a\u8fc7 --report-template \u6307\u5b9a\u62a5\u544a\u6a21\u677f\u7684\u8def\u5f84\uff0c\u7136\u540e\u6d4b\u8bd5\u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u5c31\u4f1a\u91c7\u7528\u81ea\u5b9a\u4e49\u7684\u6a21\u677f\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u3002 $ hrun docs/data/demo-quickstart-2.yml --report-template /path/to/custom_report_template ... \u540c\u4e0a\uff0c\u7701\u7565 INFO render with html report template: /path/to/custom_report_template INFO Start to render Html report ... INFO Generated Html report: reports/1532078874.html","title":"\u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u677f"},{"location":"run-tests/report/#_5","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\u3002\u5982\u9700\u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u8def\u5f84\uff0c\u53ef\u4ee5\u4f7f\u7528 --report-dir \u53c2\u6570\u3002 $ hrun docs/data/demo-quickstart-2.yml --dirreport-name /other/path/ ... \u540c\u4e0a\uff0c\u7701\u7565 INFO Start to render Html report ... INFO Generated Html report: /other/path/1532078874.html","title":"\u6307\u5b9a\u62a5\u544a\u751f\u6210\u8def\u5f84"}]} \ No newline at end of file +{"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"HttpRunner \u662f\u4e00\u6b3e\u9762\u5411 HTTP(S) \u534f\u8bae\u7684\u901a\u7528\u6d4b\u8bd5\u6846\u67b6\uff0c\u53ea\u9700\u7f16\u5199\u7ef4\u62a4\u4e00\u4efd YAML/JSON \u811a\u672c\uff0c\u5373\u53ef\u5b9e\u73b0\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u6027\u80fd\u6d4b\u8bd5\u3001\u7ebf\u4e0a\u76d1\u63a7\u3001\u6301\u7eed\u96c6\u6210\u7b49\u591a\u79cd\u6d4b\u8bd5\u9700\u6c42\u3002 \u6b64\u6587\u6863\u9002\u7528\u4e8e\u5168\u65b0\u53d1\u5e03\u7684 HttpRunner 2.x \u7248\u672c\uff0c 1.x \u7248\u672c\u7684\u4f7f\u7528\u6587\u6863\u8bf7\u67e5\u770b \u5386\u53f2\u94fe\u63a5 \u3002 \u8bbe\u8ba1\u7406\u5ff5 \u00b6 \u5145\u5206\u590d\u7528\u4f18\u79c0\u7684\u5f00\u6e90\u9879\u76ee\uff0c\u4e0d\u8ffd\u6c42\u91cd\u590d\u9020\u8f6e\u5b50\uff0c\u800c\u662f\u5c06\u5f3a\u5927\u7684\u8f6e\u5b50\u7ec4\u88c5\u6210\u6218\u8f66 \u9075\u5faa \u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e \u7684\u51c6\u5219\uff0c\u5728\u6846\u67b6\u529f\u80fd\u4e2d\u878d\u5165\u81ea\u52a8\u5316\u6d4b\u8bd5\u6700\u4f73\u5de5\u7a0b\u5b9e\u8df5 \u8ffd\u6c42\u6295\u5165\u4ea7\u51fa\u6bd4\uff0c\u4e00\u4efd\u6295\u5165\u5373\u53ef\u5b9e\u73b0\u591a\u79cd\u6d4b\u8bd5\u9700\u6c42 \u6838\u5fc3\u7279\u6027 \u00b6 \u7ee7\u627f Requests \u7684\u5168\u90e8\u7279\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0 HTTP(S) \u7684\u5404\u79cd\u6d4b\u8bd5\u9700\u6c42 \u91c7\u7528 YAML/JSON \u7684\u5f62\u5f0f\u63cf\u8ff0\u6d4b\u8bd5\u573a\u666f\uff0c\u4fdd\u969c\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u7684\u7edf\u4e00\u6027\u548c\u53ef\u7ef4\u62a4\u6027 \u501f\u52a9\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\uff0c\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u8f7b\u677e\u5b9e\u73b0\u590d\u6742\u7684\u52a8\u6001\u8ba1\u7b97\u903b\u8f91 \u652f\u6301\u5b8c\u5584\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff0c\u5145\u5206\u5b9e\u73b0\u6d4b\u8bd5\u7528\u4f8b\u7684\u590d\u7528 \u6d4b\u8bd5\u524d\u540e\u652f\u6301\u5b8c\u5584\u7684 hook \u673a\u5236 \u54cd\u5e94\u7ed3\u679c\u652f\u6301\u4e30\u5bcc\u7684\u6821\u9a8c\u673a\u5236 \u57fa\u4e8e HAR \u5b9e\u73b0\u63a5\u53e3\u5f55\u5236\u548c\u7528\u4f8b\u751f\u6210\u529f\u80fd\uff08 har2case \uff09 \u7ed3\u5408 Locust \u6846\u67b6\uff0c\u65e0\u9700\u989d\u5916\u7684\u5de5\u4f5c\u5373\u53ef\u5b9e\u73b0\u5206\u5e03\u5f0f\u6027\u80fd\u6d4b\u8bd5 \u6267\u884c\u65b9\u5f0f\u91c7\u7528 CLI \u8c03\u7528\uff0c\u53ef\u4e0e Jenkins \u7b49\u6301\u7eed\u96c6\u6210\u5de5\u5177\u5b8c\u7f8e\u7ed3\u5408 \u6d4b\u8bd5\u7ed3\u679c\u7edf\u8ba1\u62a5\u544a\u7b80\u6d01\u6e05\u6670\uff0c\u9644\u5e26\u8be6\u5c3d\u7edf\u8ba1\u4fe1\u606f\u548c\u65e5\u5fd7\u8bb0\u5f55 \u6781\u5f3a\u7684\u53ef\u6269\u5c55\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0\u4e8c\u6b21\u5f00\u53d1\u548c Web \u5e73\u53f0\u5316 \u66f4\u591a\u4fe1\u606f \u00b6 \u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"\u4ecb\u7ecd"},{"location":"#_1","text":"\u5145\u5206\u590d\u7528\u4f18\u79c0\u7684\u5f00\u6e90\u9879\u76ee\uff0c\u4e0d\u8ffd\u6c42\u91cd\u590d\u9020\u8f6e\u5b50\uff0c\u800c\u662f\u5c06\u5f3a\u5927\u7684\u8f6e\u5b50\u7ec4\u88c5\u6210\u6218\u8f66 \u9075\u5faa \u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e \u7684\u51c6\u5219\uff0c\u5728\u6846\u67b6\u529f\u80fd\u4e2d\u878d\u5165\u81ea\u52a8\u5316\u6d4b\u8bd5\u6700\u4f73\u5de5\u7a0b\u5b9e\u8df5 \u8ffd\u6c42\u6295\u5165\u4ea7\u51fa\u6bd4\uff0c\u4e00\u4efd\u6295\u5165\u5373\u53ef\u5b9e\u73b0\u591a\u79cd\u6d4b\u8bd5\u9700\u6c42","title":"\u8bbe\u8ba1\u7406\u5ff5"},{"location":"#_2","text":"\u7ee7\u627f Requests \u7684\u5168\u90e8\u7279\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0 HTTP(S) \u7684\u5404\u79cd\u6d4b\u8bd5\u9700\u6c42 \u91c7\u7528 YAML/JSON \u7684\u5f62\u5f0f\u63cf\u8ff0\u6d4b\u8bd5\u573a\u666f\uff0c\u4fdd\u969c\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u7684\u7edf\u4e00\u6027\u548c\u53ef\u7ef4\u62a4\u6027 \u501f\u52a9\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\uff0c\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u8f7b\u677e\u5b9e\u73b0\u590d\u6742\u7684\u52a8\u6001\u8ba1\u7b97\u903b\u8f91 \u652f\u6301\u5b8c\u5584\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff0c\u5145\u5206\u5b9e\u73b0\u6d4b\u8bd5\u7528\u4f8b\u7684\u590d\u7528 \u6d4b\u8bd5\u524d\u540e\u652f\u6301\u5b8c\u5584\u7684 hook \u673a\u5236 \u54cd\u5e94\u7ed3\u679c\u652f\u6301\u4e30\u5bcc\u7684\u6821\u9a8c\u673a\u5236 \u57fa\u4e8e HAR \u5b9e\u73b0\u63a5\u53e3\u5f55\u5236\u548c\u7528\u4f8b\u751f\u6210\u529f\u80fd\uff08 har2case \uff09 \u7ed3\u5408 Locust \u6846\u67b6\uff0c\u65e0\u9700\u989d\u5916\u7684\u5de5\u4f5c\u5373\u53ef\u5b9e\u73b0\u5206\u5e03\u5f0f\u6027\u80fd\u6d4b\u8bd5 \u6267\u884c\u65b9\u5f0f\u91c7\u7528 CLI \u8c03\u7528\uff0c\u53ef\u4e0e Jenkins \u7b49\u6301\u7eed\u96c6\u6210\u5de5\u5177\u5b8c\u7f8e\u7ed3\u5408 \u6d4b\u8bd5\u7ed3\u679c\u7edf\u8ba1\u62a5\u544a\u7b80\u6d01\u6e05\u6670\uff0c\u9644\u5e26\u8be6\u5c3d\u7edf\u8ba1\u4fe1\u606f\u548c\u65e5\u5fd7\u8bb0\u5f55 \u6781\u5f3a\u7684\u53ef\u6269\u5c55\u6027\uff0c\u8f7b\u677e\u5b9e\u73b0\u4e8c\u6b21\u5f00\u53d1\u548c Web \u5e73\u53f0\u5316","title":"\u6838\u5fc3\u7279\u6027"},{"location":"#_3","text":"\u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"\u66f4\u591a\u4fe1\u606f"},{"location":"CHANGELOG/","text":"Release History \u00b6 2.3.2 (2019-11-01) \u00b6 Changed make render_html_report separate with HttpRunner().run_tests() --report-file : specify report file path, this has higher priority than specifying report dir. remove summary property from HttpRunner 2.3.1 (2019-10-28) \u00b6 Fixed fix locusts entry configuration Changed update PyPi classifiers 2.3.0 (2019-10-27) \u00b6 Added feat: implement plugin system prototype, make locusts as plugin test: add Python 3.8 to Travis-CI feat: add __main__.py , python -m httprunner can be used to hrun tests Changed update dependency versions in pyproject.toml rename folder, httprunner/templates => httprunner/static log httprunner version before running tests remove unused import & code Fixed fix #707: duration stat error in multiple testsuites 2.2.6 (2019-09-18) \u00b6 Added feat: config variables support parsing from function feat: support jsonpath to parse json response #679 feat: generate html report with specified report file #704 Changed remove unused import adjust code format Fixed fix: dev-rules link 404 2.2.5 (2019-07-28) \u00b6 Added log HttpRunner version when initializing Fixed fix #658: sys.exit 1 if any testcase failed fix ModuleNotFoundError in debugging mode if httprunner uninstalled 2.2.4 (2019-07-18) \u00b6 Changed replace pipenv & setup.py with poetry drop support for Python 3.4 as it was EOL on 2019-03-16 relocate debugging scripts, move from main-debug.py to httprunner.cli Fixed fix #574: delete unnecessary code fix #551: raise if times is not digit fix #572: tests_def_mapping[\"testcases\"] typo error 2.2.3 (2019-06-30) \u00b6 Fixed fix yaml FullLoader AttributeError when PyYAML version < 5.1 2.2.2 (2019-06-26) \u00b6 Changed extract is used to replace output when passing former teststep's (as a testcase) export value to next teststep export is used to replace output in testcase config 2.2.1 (2019-06-25) \u00b6 Added add demo api/testcase/testsuite to new created scaffold project update default .gitignore of new created scaffold project add demo content to debugtalk.py / .env of new created scaffold project Fixed fix extend with testcase reference in format version 2 fix ImportError when locustio is not installed fix YAMLLoadWarning by specify yaml loader 2.2.0 (2019-06-24) \u00b6 Added support testcase/testsuite in format version 2 Fixed add wheel in dev packages fix exception when teststep name reference former extracted variable 2.1.3 (2019-04-24) \u00b6 Fixed replace eval mechanism with builtins to prevent security vulnerabilities ImportError for builtins in Python2.7 2.1.2 (2019-04-17) \u00b6 Added support new variable notation ${var} use \\$\\$ to escape \\$ notation add Python 3.7 for travis CI Fixed match duplicate variable/function in single raw string escape '{' and '}' notation in raw string print_info: TypeError when value is None display api name when running api as testcase 2.1.1 (2019-04-11) \u00b6 Changed refactor upload files mechanism with requests-toolbelt : simplify usage syntax, detect mimetype with filetype . support upload multiple fields. 2.1.0 (2019-04-10) \u00b6 Added implement json dump Python objects when save tests implement lazy parser remove project_mapping from parse_tests result Fixed reference output variables pass output variables between testcases 2.0.6 (2019-03-18) \u00b6 Added create .gitignore file when initializing new project Fixed fix CSV relative path detection fix current validators displaying the former one when they are empty 2.0.5 (2019-03-04) \u00b6 Added implement method to get variables and output Fixed fix xss in response json 2.0.4 (2019-02-28) \u00b6 Fixed fix verify priority with nested testcase fix function in config variables called multiple times dump loaded tests when running tests_mapping directly 2.0.3 (2019-02-24) \u00b6 Fixed fix verify priority: teststep > config fix Chinese charactor in log_file encoding error in Windows fix dump file with Chinese charactor in Python 3 2.0.2 (2019-01-21) \u00b6 Fixed each teststeps in one testcase share the same session fix duplicate API definition output Changed display result from hook functions in DEBUG level log change log level of \"Variables & Output\" to INFO print Invalid testcase path or testcases print testcase output in INFO level log 2.0.1 (2019-01-18) \u00b6 Fixed override current teststep variables with former testcase output variables Fixed compatibility when testcase name is empty skip undefined variable when parsing string content Changed add back request method in report 2.0.0 (2019-01-01) \u00b6 Changed Massive Refactor and Simplification Redesign testcase structure Module pipline Start Semantic Versioning Switch to Apache 2.0 license Change logo","title":"CHANGELOG"},{"location":"CHANGELOG/#release-history","text":"","title":"Release History"},{"location":"CHANGELOG/#232-2019-11-01","text":"Changed make render_html_report separate with HttpRunner().run_tests() --report-file : specify report file path, this has higher priority than specifying report dir. remove summary property from HttpRunner","title":"2.3.2 (2019-11-01)"},{"location":"CHANGELOG/#231-2019-10-28","text":"Fixed fix locusts entry configuration Changed update PyPi classifiers","title":"2.3.1 (2019-10-28)"},{"location":"CHANGELOG/#230-2019-10-27","text":"Added feat: implement plugin system prototype, make locusts as plugin test: add Python 3.8 to Travis-CI feat: add __main__.py , python -m httprunner can be used to hrun tests Changed update dependency versions in pyproject.toml rename folder, httprunner/templates => httprunner/static log httprunner version before running tests remove unused import & code Fixed fix #707: duration stat error in multiple testsuites","title":"2.3.0 (2019-10-27)"},{"location":"CHANGELOG/#226-2019-09-18","text":"Added feat: config variables support parsing from function feat: support jsonpath to parse json response #679 feat: generate html report with specified report file #704 Changed remove unused import adjust code format Fixed fix: dev-rules link 404","title":"2.2.6 (2019-09-18)"},{"location":"CHANGELOG/#225-2019-07-28","text":"Added log HttpRunner version when initializing Fixed fix #658: sys.exit 1 if any testcase failed fix ModuleNotFoundError in debugging mode if httprunner uninstalled","title":"2.2.5 (2019-07-28)"},{"location":"CHANGELOG/#224-2019-07-18","text":"Changed replace pipenv & setup.py with poetry drop support for Python 3.4 as it was EOL on 2019-03-16 relocate debugging scripts, move from main-debug.py to httprunner.cli Fixed fix #574: delete unnecessary code fix #551: raise if times is not digit fix #572: tests_def_mapping[\"testcases\"] typo error","title":"2.2.4 (2019-07-18)"},{"location":"CHANGELOG/#223-2019-06-30","text":"Fixed fix yaml FullLoader AttributeError when PyYAML version < 5.1","title":"2.2.3 (2019-06-30)"},{"location":"CHANGELOG/#222-2019-06-26","text":"Changed extract is used to replace output when passing former teststep's (as a testcase) export value to next teststep export is used to replace output in testcase config","title":"2.2.2 (2019-06-26)"},{"location":"CHANGELOG/#221-2019-06-25","text":"Added add demo api/testcase/testsuite to new created scaffold project update default .gitignore of new created scaffold project add demo content to debugtalk.py / .env of new created scaffold project Fixed fix extend with testcase reference in format version 2 fix ImportError when locustio is not installed fix YAMLLoadWarning by specify yaml loader","title":"2.2.1 (2019-06-25)"},{"location":"CHANGELOG/#220-2019-06-24","text":"Added support testcase/testsuite in format version 2 Fixed add wheel in dev packages fix exception when teststep name reference former extracted variable","title":"2.2.0 (2019-06-24)"},{"location":"CHANGELOG/#213-2019-04-24","text":"Fixed replace eval mechanism with builtins to prevent security vulnerabilities ImportError for builtins in Python2.7","title":"2.1.3 (2019-04-24)"},{"location":"CHANGELOG/#212-2019-04-17","text":"Added support new variable notation ${var} use \\$\\$ to escape \\$ notation add Python 3.7 for travis CI Fixed match duplicate variable/function in single raw string escape '{' and '}' notation in raw string print_info: TypeError when value is None display api name when running api as testcase","title":"2.1.2 (2019-04-17)"},{"location":"CHANGELOG/#211-2019-04-11","text":"Changed refactor upload files mechanism with requests-toolbelt : simplify usage syntax, detect mimetype with filetype . support upload multiple fields.","title":"2.1.1 (2019-04-11)"},{"location":"CHANGELOG/#210-2019-04-10","text":"Added implement json dump Python objects when save tests implement lazy parser remove project_mapping from parse_tests result Fixed reference output variables pass output variables between testcases","title":"2.1.0 (2019-04-10)"},{"location":"CHANGELOG/#206-2019-03-18","text":"Added create .gitignore file when initializing new project Fixed fix CSV relative path detection fix current validators displaying the former one when they are empty","title":"2.0.6 (2019-03-18)"},{"location":"CHANGELOG/#205-2019-03-04","text":"Added implement method to get variables and output Fixed fix xss in response json","title":"2.0.5 (2019-03-04)"},{"location":"CHANGELOG/#204-2019-02-28","text":"Fixed fix verify priority with nested testcase fix function in config variables called multiple times dump loaded tests when running tests_mapping directly","title":"2.0.4 (2019-02-28)"},{"location":"CHANGELOG/#203-2019-02-24","text":"Fixed fix verify priority: teststep > config fix Chinese charactor in log_file encoding error in Windows fix dump file with Chinese charactor in Python 3","title":"2.0.3 (2019-02-24)"},{"location":"CHANGELOG/#202-2019-01-21","text":"Fixed each teststeps in one testcase share the same session fix duplicate API definition output Changed display result from hook functions in DEBUG level log change log level of \"Variables & Output\" to INFO print Invalid testcase path or testcases print testcase output in INFO level log","title":"2.0.2 (2019-01-21)"},{"location":"CHANGELOG/#201-2019-01-18","text":"Fixed override current teststep variables with former testcase output variables Fixed compatibility when testcase name is empty skip undefined variable when parsing string content Changed add back request method in report","title":"2.0.1 (2019-01-18)"},{"location":"CHANGELOG/#200-2019-01-01","text":"Changed Massive Refactor and Simplification Redesign testcase structure Module pipline Start Semantic Versioning Switch to Apache 2.0 license Change logo","title":"2.0.0 (2019-01-01)"},{"location":"FAQ/","text":"\u5e38\u89c1\u95ee\u9898 \u00b6","title":"FAQ"},{"location":"FAQ/#_1","text":"","title":"\u5e38\u89c1\u95ee\u9898"},{"location":"Installation/","text":"\u8fd0\u884c\u73af\u5883 \u00b6 HttpRunner \u662f\u4e00\u4e2a\u57fa\u4e8e Python \u5f00\u53d1\u7684\u6d4b\u8bd5\u6846\u67b6\uff0c\u53ef\u4ee5\u8fd0\u884c\u5728 macOS\u3001Linux\u3001Windows \u7cfb\u7edf\u5e73\u53f0\u4e0a\u3002 Python \u7248\u672c \uff1aHttpRunner \u652f\u6301 Python 3.4 \u53ca\u4ee5\u4e0a\u7684\u6240\u6709\u7248\u672c\uff0c\u5e76\u4f7f\u7528 Travis-CI \u8fdb\u884c\u4e86 \u6301\u7eed\u96c6\u6210\u6d4b\u8bd5 \uff0c\u6d4b\u8bd5\u8986\u76d6\u7684\u7248\u672c\u5305\u62ec 2.7/3.4/3.5/3.6/3.7\u3002\u867d\u7136 HttpRunner \u6682\u65f6\u4fdd\u7559\u4e86\u5bf9 Python 2.7 \u7684\u517c\u5bb9\u652f\u6301\uff0c\u4f46\u5f3a\u70c8\u5efa\u8bae\u4f7f\u7528 Python 3.4 \u53ca\u4ee5\u4e0a\u7248\u672c\u3002 \u64cd\u4f5c\u7cfb\u7edf \uff1a\u63a8\u8350\u4f7f\u7528 macOS/Linux\u3002 \u5b89\u88c5\u65b9\u5f0f \u00b6 HttpRunner \u7684\u7a33\u5b9a\u7248\u672c\u6258\u7ba1\u5728 PyPI \u4e0a\uff0c\u53ef\u4ee5\u4f7f\u7528 pip \u8fdb\u884c\u5b89\u88c5\u3002 $ pip install httprunner \u5982\u679c\u4f60\u9700\u8981\u4f7f\u7528\u6700\u65b0\u7684\u5f00\u53d1\u7248\u672c\uff0c\u90a3\u4e48\u53ef\u4ee5\u91c7\u7528\u9879\u76ee\u7684 GitHub \u4ed3\u5e93\u5730\u5740\u8fdb\u884c\u5b89\u88c5\uff1a $ pip install git+https://github.com/HttpRunner/HttpRunner.git@master \u7248\u672c\u5347\u7ea7 \u00b6 \u5047\u5982\u4f60\u4e4b\u524d\u5df2\u7ecf\u5b89\u88c5\u8fc7\u4e86 HttpRunner\uff0c\u73b0\u5728\u9700\u8981\u5347\u7ea7\u5230\u6700\u65b0\u7248\u672c\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528 -U \u53c2\u6570\u3002\u8be5\u53c2\u6570\u5bf9\u4ee5\u4e0a\u4e09\u79cd\u5b89\u88c5\u65b9\u5f0f\u5747\u751f\u6548\u3002 $ pip install -U HttpRunner $ pip install -U git+https://github.com/HttpRunner/HttpRunner.git@master \u5b89\u88c5\u6821\u9a8c \u00b6 \u5728 HttpRunner \u5b89\u88c5\u6210\u529f\u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e\u5982\u4e0b 5 \u4e2a\u547d\u4ee4\uff1a httprunner : \u6838\u5fc3\u547d\u4ee4 ate : \u66fe\u7ecf\u7528\u8fc7\u7684\u547d\u4ee4\uff08\u5f53\u65f6\u6846\u67b6\u540d\u79f0\u4e3a ApiTestEngine\uff09\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c hrun : httprunner \u7684\u7f29\u5199\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c locusts : \u57fa\u4e8e Locust \u5b9e\u73b0 \u6027\u80fd\u6d4b\u8bd5 har2case : \u8f85\u52a9\u5de5\u5177\uff0c\u53ef\u5c06\u6807\u51c6\u901a\u7528\u7684 HAR \u683c\u5f0f\uff08HTTP Archive\uff09\u8f6c\u6362\u4e3a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b httprunner\u3001hrun\u3001ate \u4e09\u4e2a\u547d\u4ee4\u5b8c\u5168\u7b49\u4ef7\uff0c\u529f\u80fd\u7279\u6027\u5b8c\u5168\u76f8\u540c\uff0c\u4e2a\u4eba\u63a8\u8350\u4f7f\u7528 hrun \u547d\u4ee4\u3002 \u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u82e5\u6b63\u5e38\u663e\u793a\u7248\u672c\u53f7\uff0c\u5219\u8bf4\u660e HttpRunner \u5b89\u88c5\u6210\u529f\u3002 $ hrun -V 2.0.2 $ har2case -V 0.2.0 \u5f00\u53d1\u8005\u6a21\u5f0f \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b89\u88c5 HttpRunner \u7684\u65f6\u5019\u53ea\u4f1a\u5b89\u88c5\u8fd0\u884c HttpRunner \u7684\u5fc5\u8981\u4f9d\u8d56\u5e93\u3002 \u5982\u679c\u4f60\u4e0d\u4ec5\u4ec5\u662f\u4f7f\u7528 HttpRunner\uff0c\u8fd8\u9700\u8981\u5bf9 HttpRunner \u8fdb\u884c\u5f00\u53d1\u8c03\u8bd5\uff08debug\uff09\uff0c\u90a3\u4e48\u5c31\u9700\u8981\u8fdb\u884c\u5982\u4e0b\u64cd\u4f5c\u3002 HttpRunner \u4f7f\u7528 pipenv \u5bf9\u4f9d\u8d56\u5305\u8fdb\u884c\u7ba1\u7406\uff0c\u82e5\u4f60\u8fd8\u6ca1\u6709\u5b89\u88c5 pipenv\uff0c\u9700\u8981\u5148\u6267\u884c\u5982\u4e0b\u547d\u4ee4\u8fdb\u884c\u6309\u7167\uff1a $ pip install pipenv \u83b7\u53d6 HttpRunner \u6e90\u7801\uff1a $ git clone https://github.com/HttpRunner/HttpRunner.git \u8fdb\u5165\u4ed3\u5e93\u76ee\u5f55\uff0c\u5b89\u88c5\u6240\u6709\u4f9d\u8d56\uff1a $ pipenv install --dev \u8fd0\u884c\u5355\u5143\u6d4b\u8bd5\uff0c\u82e5\u6d4b\u8bd5\u5168\u90e8\u901a\u8fc7\uff0c\u5219\u8bf4\u660e\u73af\u5883\u6b63\u5e38\u3002 $ pipenv run python -m unittest discover \u67e5\u770b HttpRunner \u7684\u4f9d\u8d56\u60c5\u51b5\uff1a $ pipenv graph HttpRunner==2.0.0 - colorama [required: Any, installed: 0.4.0] - colorlog [required: Any, installed: 3.1.4] - har2case [required: Any, installed: 0.2.0] - PyYAML [required: Any, installed: 3.13] - Jinja2 [required: Any, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - PyYAML [required: Any, installed: 3.13] - requests [required: Any, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] - requests-toolbelt [required: Any, installed: 0.8.0] - requests [required: >=2.0.1,<3.0.0, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] \u8c03\u8bd5\u8fd0\u884c\u65b9\u5f0f\uff1a # \u8c03\u8bd5\u8fd0\u884c hrun $ pipenv run python main-debug.py hrun -h # \u8c03\u8bd5\u8fd0\u884c locusts $ pipenv run python main-debug.py locusts -h Docker \u00b6 TODO","title":"\u5b89\u88c5\u8bf4\u660e"},{"location":"Installation/#_1","text":"HttpRunner \u662f\u4e00\u4e2a\u57fa\u4e8e Python \u5f00\u53d1\u7684\u6d4b\u8bd5\u6846\u67b6\uff0c\u53ef\u4ee5\u8fd0\u884c\u5728 macOS\u3001Linux\u3001Windows \u7cfb\u7edf\u5e73\u53f0\u4e0a\u3002 Python \u7248\u672c \uff1aHttpRunner \u652f\u6301 Python 3.4 \u53ca\u4ee5\u4e0a\u7684\u6240\u6709\u7248\u672c\uff0c\u5e76\u4f7f\u7528 Travis-CI \u8fdb\u884c\u4e86 \u6301\u7eed\u96c6\u6210\u6d4b\u8bd5 \uff0c\u6d4b\u8bd5\u8986\u76d6\u7684\u7248\u672c\u5305\u62ec 2.7/3.4/3.5/3.6/3.7\u3002\u867d\u7136 HttpRunner \u6682\u65f6\u4fdd\u7559\u4e86\u5bf9 Python 2.7 \u7684\u517c\u5bb9\u652f\u6301\uff0c\u4f46\u5f3a\u70c8\u5efa\u8bae\u4f7f\u7528 Python 3.4 \u53ca\u4ee5\u4e0a\u7248\u672c\u3002 \u64cd\u4f5c\u7cfb\u7edf \uff1a\u63a8\u8350\u4f7f\u7528 macOS/Linux\u3002","title":"\u8fd0\u884c\u73af\u5883"},{"location":"Installation/#_2","text":"HttpRunner \u7684\u7a33\u5b9a\u7248\u672c\u6258\u7ba1\u5728 PyPI \u4e0a\uff0c\u53ef\u4ee5\u4f7f\u7528 pip \u8fdb\u884c\u5b89\u88c5\u3002 $ pip install httprunner \u5982\u679c\u4f60\u9700\u8981\u4f7f\u7528\u6700\u65b0\u7684\u5f00\u53d1\u7248\u672c\uff0c\u90a3\u4e48\u53ef\u4ee5\u91c7\u7528\u9879\u76ee\u7684 GitHub \u4ed3\u5e93\u5730\u5740\u8fdb\u884c\u5b89\u88c5\uff1a $ pip install git+https://github.com/HttpRunner/HttpRunner.git@master","title":"\u5b89\u88c5\u65b9\u5f0f"},{"location":"Installation/#_3","text":"\u5047\u5982\u4f60\u4e4b\u524d\u5df2\u7ecf\u5b89\u88c5\u8fc7\u4e86 HttpRunner\uff0c\u73b0\u5728\u9700\u8981\u5347\u7ea7\u5230\u6700\u65b0\u7248\u672c\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528 -U \u53c2\u6570\u3002\u8be5\u53c2\u6570\u5bf9\u4ee5\u4e0a\u4e09\u79cd\u5b89\u88c5\u65b9\u5f0f\u5747\u751f\u6548\u3002 $ pip install -U HttpRunner $ pip install -U git+https://github.com/HttpRunner/HttpRunner.git@master","title":"\u7248\u672c\u5347\u7ea7"},{"location":"Installation/#_4","text":"\u5728 HttpRunner \u5b89\u88c5\u6210\u529f\u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e\u5982\u4e0b 5 \u4e2a\u547d\u4ee4\uff1a httprunner : \u6838\u5fc3\u547d\u4ee4 ate : \u66fe\u7ecf\u7528\u8fc7\u7684\u547d\u4ee4\uff08\u5f53\u65f6\u6846\u67b6\u540d\u79f0\u4e3a ApiTestEngine\uff09\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c hrun : httprunner \u7684\u7f29\u5199\uff0c\u529f\u80fd\u4e0e httprunner \u5b8c\u5168\u76f8\u540c locusts : \u57fa\u4e8e Locust \u5b9e\u73b0 \u6027\u80fd\u6d4b\u8bd5 har2case : \u8f85\u52a9\u5de5\u5177\uff0c\u53ef\u5c06\u6807\u51c6\u901a\u7528\u7684 HAR \u683c\u5f0f\uff08HTTP Archive\uff09\u8f6c\u6362\u4e3a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b httprunner\u3001hrun\u3001ate \u4e09\u4e2a\u547d\u4ee4\u5b8c\u5168\u7b49\u4ef7\uff0c\u529f\u80fd\u7279\u6027\u5b8c\u5168\u76f8\u540c\uff0c\u4e2a\u4eba\u63a8\u8350\u4f7f\u7528 hrun \u547d\u4ee4\u3002 \u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u82e5\u6b63\u5e38\u663e\u793a\u7248\u672c\u53f7\uff0c\u5219\u8bf4\u660e HttpRunner \u5b89\u88c5\u6210\u529f\u3002 $ hrun -V 2.0.2 $ har2case -V 0.2.0","title":"\u5b89\u88c5\u6821\u9a8c"},{"location":"Installation/#_5","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b89\u88c5 HttpRunner \u7684\u65f6\u5019\u53ea\u4f1a\u5b89\u88c5\u8fd0\u884c HttpRunner \u7684\u5fc5\u8981\u4f9d\u8d56\u5e93\u3002 \u5982\u679c\u4f60\u4e0d\u4ec5\u4ec5\u662f\u4f7f\u7528 HttpRunner\uff0c\u8fd8\u9700\u8981\u5bf9 HttpRunner \u8fdb\u884c\u5f00\u53d1\u8c03\u8bd5\uff08debug\uff09\uff0c\u90a3\u4e48\u5c31\u9700\u8981\u8fdb\u884c\u5982\u4e0b\u64cd\u4f5c\u3002 HttpRunner \u4f7f\u7528 pipenv \u5bf9\u4f9d\u8d56\u5305\u8fdb\u884c\u7ba1\u7406\uff0c\u82e5\u4f60\u8fd8\u6ca1\u6709\u5b89\u88c5 pipenv\uff0c\u9700\u8981\u5148\u6267\u884c\u5982\u4e0b\u547d\u4ee4\u8fdb\u884c\u6309\u7167\uff1a $ pip install pipenv \u83b7\u53d6 HttpRunner \u6e90\u7801\uff1a $ git clone https://github.com/HttpRunner/HttpRunner.git \u8fdb\u5165\u4ed3\u5e93\u76ee\u5f55\uff0c\u5b89\u88c5\u6240\u6709\u4f9d\u8d56\uff1a $ pipenv install --dev \u8fd0\u884c\u5355\u5143\u6d4b\u8bd5\uff0c\u82e5\u6d4b\u8bd5\u5168\u90e8\u901a\u8fc7\uff0c\u5219\u8bf4\u660e\u73af\u5883\u6b63\u5e38\u3002 $ pipenv run python -m unittest discover \u67e5\u770b HttpRunner \u7684\u4f9d\u8d56\u60c5\u51b5\uff1a $ pipenv graph HttpRunner==2.0.0 - colorama [required: Any, installed: 0.4.0] - colorlog [required: Any, installed: 3.1.4] - har2case [required: Any, installed: 0.2.0] - PyYAML [required: Any, installed: 3.13] - Jinja2 [required: Any, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - PyYAML [required: Any, installed: 3.13] - requests [required: Any, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] - requests-toolbelt [required: Any, installed: 0.8.0] - requests [required: >=2.0.1,<3.0.0, installed: 2.20.0] - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24] \u8c03\u8bd5\u8fd0\u884c\u65b9\u5f0f\uff1a # \u8c03\u8bd5\u8fd0\u884c hrun $ pipenv run python main-debug.py hrun -h # \u8c03\u8bd5\u8fd0\u884c locusts $ pipenv run python main-debug.py locusts -h","title":"\u5f00\u53d1\u8005\u6a21\u5f0f"},{"location":"Installation/#docker","text":"TODO","title":"Docker"},{"location":"quickstart/","text":"\u672c\u6587\u5c06\u901a\u8fc7\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\u6765\u5c55\u793a HttpRunner \u7684\u6838\u5fc3\u529f\u80fd\u4f7f\u7528\u65b9\u6cd5\u3002 \u6848\u4f8b\u4ecb\u7ecd \u00b6 \u8be5\u6848\u4f8b\u4f5c\u4e3a\u88ab\u6d4b\u670d\u52a1\uff0c\u4e3b\u8981\u6709\u4e24\u7c7b\u63a5\u53e3\uff1a \u6743\u9650\u6821\u9a8c\uff0c\u83b7\u53d6 token \u652f\u6301 CRUD \u64cd\u4f5c\u7684 RESTful APIs\uff0c\u6240\u6709\u63a5\u53e3\u7684\u8bf7\u6c42\u5934\u57df\u4e2d\u90fd\u5fc5\u987b\u5305\u542b\u6709\u6548\u7684 token \u6848\u4f8b\u7684\u5b9e\u73b0\u5f62\u5f0f\u4e3a flask \u5e94\u7528\u670d\u52a1\uff08 api_server.py \uff09\uff0c\u542f\u52a8\u65b9\u5f0f\u5982\u4e0b\uff1a $ export FLASK_APP=docs/data/api_server.py $ export FLASK_ENV=development $ flask run * Serving Flask app \"docs/data/api_server.py\" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 989-476-348 \u670d\u52a1\u542f\u52a8\u6210\u529f\u540e\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u5bf9\u5176\u8fdb\u884c\u6d4b\u8bd5\u4e86\u3002 \u6d4b\u8bd5\u51c6\u5907 \u00b6 \u6293\u5305\u5206\u6790 \u00b6 \u5728\u5f00\u59cb\u6d4b\u8bd5\u4e4b\u524d\uff0c\u6211\u4eec\u9700\u8981\u5148\u4e86\u89e3\u63a5\u53e3\u7684\u8bf7\u6c42\u548c\u54cd\u5e94\u7ec6\u8282\uff0c\u800c\u6700\u4f73\u7684\u65b9\u5f0f\u5c31\u662f\u91c7\u7528 Charles Proxy \u6216\u8005 Fiddler \u8fd9\u7c7b\u7f51\u7edc\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u5206\u6790\u3002 \u4f8b\u5982\uff0c\u5728\u672c\u6848\u4f8b\u4e2d\uff0c\u6211\u4eec\u5148\u8fdb\u884c\u6743\u9650\u6821\u9a8c\uff0c\u7136\u540e\u6210\u529f\u521b\u5efa\u4e00\u4e2a\u7528\u6237\uff0c\u5bf9\u5e94\u7684\u7f51\u7edc\u6293\u5305\u5185\u5bb9\u5982\u4e0b\u56fe\u6240\u793a\uff1a \u901a\u8fc7\u6293\u5305\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5177\u4f53\u7684\u63a5\u53e3\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684URL\u3001Method\u3001headers\u3001\u53c2\u6570\u548c\u54cd\u5e94\u5185\u5bb9\u7b49\u5185\u5bb9\uff0c\u57fa\u4e8e\u8fd9\u4e9b\u4fe1\u606f\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u7f16\u5199\u6d4b\u8bd5\u7528\u4f8b\u4e86\u3002 \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u4e3a\u4e86\u7b80\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7f16\u5199\u5de5\u4f5c\uff0cHttpRunner \u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u7684\u529f\u80fd\u3002 \u9996\u5148\uff0c\u9700\u8981\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\uff0c\u5047\u8bbe\u5bfc\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo-quickstart.har \u3002 \u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo-quickstart.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\uff0c\u52a0\u4e0a -2y \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002\u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002\u5173\u4e8e har2case \u7684\u8be6\u7ec6\u4f7f\u7528\u8bf4\u660e\uff0c\u8bf7\u67e5\u770b \u300a\u5f55\u5236\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u300b \u3002 \u7ecf\u8fc7\u8f6c\u6362\uff0c\u5728\u6e90 demo-quickstart.har \u6587\u4ef6\u7684\u540c\u7ea7\u76ee\u5f55\u4e0b\u751f\u6210\u4e86\u76f8\u540c\u6587\u4ef6\u540d\u79f0\u7684 YAML \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6 demo-quickstart.yml \uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a - config : name : testcase description variables : {} - test : name : /api/get-token request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : 2.8.6 device_sn : FwgRiO7CNA50DSU os_platform : ios json : sign : 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98 method : POST url : http://127.0.0.1:5000/api/get-token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.token , baNLX1zhFYP11Seb ] - test : name : /api/users/1000 request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 device_sn : FwgRiO7CNA50DSU token : baNLX1zhFYP11Seb json : name : user1 password : '123456' method : POST url : http://127.0.0.1:5000/api/users/1000 validate : - eq : [ status_code , 201 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.msg , user created successfully. ] \u73b0\u5728\u6211\u4eec\u53ea\u9700\u8981\u77e5\u9053\u5982\u4e0b\u51e0\u70b9\uff1a \u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e3a\u4e00\u4e2a list of dict \u7ed3\u6784\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 config \u4e3a\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b test \u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4f5c\u7528\u57df\u4ec5\u9650\u4e8e\u672c\u8eab \u5982\u4e0a\u4fbf\u662f HttpRunner \u6d4b\u8bd5\u7528\u4f8b\u7684\u57fa\u672c\u7ed3\u6784\u3002 \u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u63cf\u8ff0\u300b \u3002 \u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u6d4b\u8bd5\u7528\u4f8b\u5c31\u7eea\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f00\u59cb\u8c03\u8bd5\u8fd0\u884c\u4e86\u3002 \u4e3a\u4e86\u6f14\u793a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8fed\u4ee3\u4f18\u5316\u8fc7\u7a0b\uff0c\u6211\u4eec\u5148\u5c06 demo-quickstart.json \u91cd\u547d\u540d\u4e3a demo-quickstart-0.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-0.yml \uff09\u3002 \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u547d\u4ee4\u4e3a hrun \uff0c\u540e\u9762\u76f4\u63a5\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\u5373\u53ef\u3002 $ hrun docs/data/demo-quickstart-0.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.26 ms, response_length: 46 bytes ERROR validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/get-token method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios'} json: {'sign': '9c0c7e51c91ae963c833a4ccbab8d683c4a90c98'} verify: True ====== response details ====== status_code: 200 headers: {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": true, \"token\": \"tXGuSQgOCVXcltkz\"}' F /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0000_000 (httprunner.api.TestSequense) /api/get-token ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.026s FAILED (failures=2) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513835.html \u975e\u5e38\u4e0d\u5e78\uff0c\u4e24\u4e2a\u63a5\u53e3\u7684\u6d4b\u8bd5\u7528\u4f8b\u5747\u8fd0\u884c\u5931\u8d25\u4e86\u3002 \u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u4ece\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u62a5\u9519\u4fe1\u606f\u548c\u5806\u6808\u4fe1\u606f\uff08Traceback\uff09\u53ef\u4ee5\u770b\u51fa\uff0c\u7b2c\u4e00\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u83b7\u53d6\u7684 token \u4e0e\u9884\u671f\u503c\u4e0d\u4e00\u81f4\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u8bf7\u6c42\u6743\u9650\u6821\u9a8c\u5931\u8d25\uff08403\uff09\u3002 \u63a5\u4e0b\u6765\u6211\u4eec\u5c06\u9010\u6b65\u8fdb\u884c\u8fdb\u884c\u4f18\u5316\u3002 \u8c03\u6574\u6821\u9a8c\u5668 \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c har2case \u751f\u6210\u7528\u4f8b\u65f6\uff0c\u82e5 HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u4f1a\u5c06\u7b2c\u4e00\u5c42\u7ea7\u4e2d\u7684\u6240\u6709 key-value \u8f6c\u6362\u4e3a validator\u3002 \u4f8b\u5982\u4e0a\u9762\u7684\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u751f\u6210\u7684 validator \u4e3a\uff1a \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]} ] \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u5c31\u4f1a\u5bf9\u4e0a\u9762\u7684\u5404\u4e2a\u9879\u8fdb\u884c\u6821\u9a8c\u3002 \u95ee\u9898\u5728\u4e8e\uff0c\u8bf7\u6c42 /api/get-token \u63a5\u53e3\u65f6\uff0c\u6bcf\u6b21\u751f\u6210\u7684 token \u90fd\u4f1a\u662f\u4e0d\u540c\u7684\uff0c\u56e0\u6b64\u5c06\u751f\u6210\u7684 token \u4f5c\u4e3a\u6821\u9a8c\u9879\u7684\u8bdd\uff0c\u6821\u9a8c\u81ea\u7136\u5c31\u65e0\u6cd5\u901a\u8fc7\u4e86\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u5e94\u8be5\u53bb\u6389\u8fd9\u7c7b\u52a8\u6001\u53d8\u5316\u7684\u503c\u3002 \u53bb\u9664\u8be5\u9879\u540e\uff0c\u5c06\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-1.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-1.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-1.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 6.61 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:45:34 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.018s FAILED (failures=1) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513934.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5df2\u7ecf\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u5931\u8d25\uff08403\uff09\uff0c\u8fd8\u662f\u56e0\u4e3a\u6743\u9650\u6821\u9a8c\u7684\u539f\u56e0\u3002 \u53c2\u6570\u5173\u8054 \u00b6 \u6211\u4eec\u7ee7\u7eed\u67e5\u770b demo-quickstart-1.json \uff0c\u4f1a\u53d1\u73b0\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42 headers \u4e2d\u7684 token \u4ecd\u7136\u662f\u786c\u7f16\u7801\u7684\uff0c\u5373\u6293\u5305\u65f6\u83b7\u53d6\u5230\u7684\u503c\u3002\u5728\u6211\u4eec\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u8fd9\u4e2a token \u5df2\u7ecf\u5931\u6548\u4e86\uff0c\u6240\u4ee5\u4f1a\u51fa\u73b0 403 \u6743\u9650\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u6211\u4eec\u5e94\u8be5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u5148\u52a8\u6001\u83b7\u53d6\u5230\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 token\uff0c\u7136\u540e\u5728\u540e\u7eed\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42\u4e2d\u4f7f\u7528\u524d\u9762\u83b7\u53d6\u5230\u7684 token\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53c2\u6570\u63d0\u53d6\uff08 extract \uff09\u548c\u53c2\u6570\u5f15\u7528\u7684\u529f\u80fd\uff08 $var \uff09\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\uff0c\u82e5\u9700\u8981\u4ece\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5219\u53ef\u4f7f\u7528 extract \u5173\u952e\u5b57\u3002extract \u7684\u5217\u8868\u4e2d\u53ef\u6307\u5b9a\u4e00\u4e2a\u6216\u591a\u4e2a\u9700\u8981\u63d0\u53d6\u7684\u53c2\u6570\u3002 \u5728\u63d0\u53d6\u53c2\u6570\u65f6\uff0c\u5f53 HTTP \u7684\u8bf7\u6c42\u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u53ef\u4ee5\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u9010\u7ea7\u5f80\u4e0b\u83b7\u53d6\u5230\u53c2\u6570\u503c\uff1b\u54cd\u5e94\u7ed3\u679c\u7684\u6574\u4f53\u5185\u5bb9\u5f15\u7528\u65b9\u5f0f\u4e3a content \u6216\u8005 body\u3002 \u4f8b\u5982\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3 /api/get-token \u7684\u54cd\u5e94\u7ed3\u679c\u4e3a\uff1a { \"success\" : true , \"token\" : \"ZQkYhbaQ6q8UFFNE\" } \u90a3\u4e48\u8981\u83b7\u53d6\u5230 token \u53c2\u6570\uff0c\u5c31\u53ef\u4ee5\u4f7f\u7528 content.token \u7684\u65b9\u5f0f\uff1b\u5177\u4f53\u7684\u5199\u6cd5\u5982\u4e0b\uff1a \"extract\" : [ { \"token\" : \"content.token\" } ] \u5176\u4e2d\uff0ctoken \u4f5c\u4e3a\u63d0\u53d6\u540e\u7684\u53c2\u6570\u540d\u79f0\uff0c\u53ef\u4ee5\u5728\u540e\u7eed\u4f7f\u7528 $token \u8fdb\u884c\u5f15\u7528\u3002 \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" , \"Content-Type\" : \"application/json\" } \u4fee\u6539\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-2.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-2.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-2.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.32 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548514191.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e5f\u8fd0\u884c\u6210\u529f\u4e86\u3002 base_url \u00b6 \u867d\u7136\u6d4b\u8bd5\u6b65\u9aa4\u8fd0\u884c\u90fd\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4ecd\u7136\u6709\u7ee7\u7eed\u4f18\u5316\u7684\u5730\u65b9\u3002 \u7ee7\u7eed\u67e5\u770b demo-quickstart-2.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684 URL \u4e2d\uff0c\u90fd\u91c7\u7528\u7684\u662f\u5b8c\u6574\u7684\u63cf\u8ff0\uff08host+path\uff09\uff0c\u4f46\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u540c\u4e00\u4e2a\u7528\u4f8b\u4e2d\u7684 host \u90fd\u662f\u76f8\u540c\u7684\uff0c\u533a\u522b\u4ec5\u5728\u4e8e path \u90e8\u5206\u3002 \u56e0\u6b64\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 URL \u7684 base_url \u62bd\u53d6\u51fa\u6765\uff0c\u653e\u5230\u5168\u5c40\u914d\u7f6e\u6a21\u5757\uff08config\uff09\u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 URL \u53ea\u4fdd\u7559 PATH \u90e8\u5206\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 - test : name : get token request : url : /api/get-token \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-3.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-3.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002 \u53d8\u91cf\u7684\u7533\u660e\u548c\u5f15\u7528 \u00b6 \u7ee7\u7eed\u67e5\u770b demo-quickstart-3.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b58\u5728\u8f83\u591a\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u4f8b\u5982 app_version\u3001device_sn\u3001os_platform\u3001user_id \u7b49\u3002 \u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u53ef\u4ee5\u4e0d\u7528\u4fee\u6539\u8fd9\u4e9b\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u8fd0\u884c\u3002\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ef4\u62a4\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u540c\u4e00\u4e2a\u53c2\u6570\u503c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u51fa\u73b0\u591a\u6b21\uff0c\u90a3\u4e48\u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5c06\u8fd9\u4e9b\u53c2\u6570\u5b9a\u4e49\u4e3a\u53d8\u91cf\uff0c\u7136\u540e\u5728\u9700\u8981\u53c2\u6570\u7684\u5730\u65b9\u8fdb\u884c\u5f15\u7528\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53d8\u91cf\u7533\u660e\uff08 variables \uff09\u548c\u5f15\u7528\uff08 $var \uff09\u7684\u673a\u5236\u3002\u5728 config \u548c test \u4e2d\u5747\u53ef\u4ee5\u901a\u8fc7 variables \u5173\u952e\u5b57\u5b9a\u4e49\u53d8\u91cf\uff0c\u7136\u540e\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u53ef\u4ee5\u901a\u8fc7 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\u5f15\u7528\u53d8\u91cf\u3002\u533a\u522b\u5728\u4e8e\uff0c\u5728 config \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4e3a\u5168\u5c40\u7684\uff0c\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6240\u6709\u5730\u65b9\u5747\u53ef\u4ee5\u5f15\u7528\uff1b\u5728 test \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4f5c\u7528\u57df\u4ec5\u5c40\u9650\u4e8e\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u3002 \u5bf9\u4e0a\u8ff0\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u786c\u7f16\u7801\u7684\u53c2\u6570\u8fdb\u884c\u53d8\u91cf\u7533\u660e\u548c\u5f15\u7528\u8c03\u6574\u540e\uff0c\u65b0\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-4.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-4.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002 \u62bd\u53d6\u516c\u5171\u53d8\u91cf \u00b6 \u67e5\u770b demo-quickstart-4.json \u53ef\u4ee5\u770b\u51fa\uff0c\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u90fd\u5b9a\u4e49\u4e86 device_sn\u3002\u9488\u5bf9\u8fd9\u7c7b\u516c\u5171\u7684\u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5176\u7edf\u4e00\u5b9a\u4e49\u5728 config \u7684 variables \u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5c31\u4e0d\u7528\u518d\u91cd\u590d\u5b9a\u4e49\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 variables : device_sn : FwgRiO7CNA50DSU \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u89c1 demo-quickstart-5.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-5.yml \uff09\u3002 \u5b9e\u73b0\u52a8\u6001\u8fd0\u7b97\u903b\u8f91 \u00b6 \u5728 demo-quickstart-5.yml \u4e2d\uff0c\u53c2\u6570 device_sn \u4ee3\u8868\u7684\u662f\u8bbe\u5907\u7684 SN \u7f16\u7801\uff0c\u867d\u7136\u91c7\u7528\u786c\u7f16\u7801\u7684\u65b9\u5f0f\u6682\u65f6\u4e0d\u5f71\u54cd\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\uff0c\u4f46\u8fd9\u4e0e\u771f\u5b9e\u7684\u7528\u6237\u573a\u666f\u4e0d\u5927\u76f8\u7b26\u3002 \u5047\u8bbe device_sn \u7684\u683c\u5f0f\u4e3a 15 \u957f\u5ea6\u7684\u5b57\u7b26\u4e32\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u9488\u5bf9 device_sn \u751f\u6210\u4e00\u4e2a 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u3002\b\u4e0e\u6b64\u540c\u65f6\uff0csign \u5b57\u6bb5\u662f\u6839\u636e headers \u4e2d\u7684\u5404\u4e2a\u5b57\u6bb5\u62fc\u63a5\u540e\u751f\u6210\u5f97\u5230\u7684 MD5 \u503c\uff0c\u56e0\u6b64\u5728 device_sn \u53d8\u52a8\u540e\uff0csign \u4e5f\u5e94\u8be5\u91cd\u65b0\u8fdb\u884c\u8ba1\u7b97\uff0c\u5426\u5219\u5c31\u4f1a\u518d\u6b21\u51fa\u73b0\u7b7e\u540d\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u7136\u800c\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u91c7\u7528 YAML/JSON \u683c\u5f0f\u8fdb\u884c\u63cf\u8ff0\u7684\uff0c\u5728\u6587\u672c\u683c\u5f0f\u4e2d\u5982\u4f55\u6267\u884c\u4ee3\u7801\u8fd0\u7b97\u5462\uff1f HttpRunner \u7684\u5b9e\u73b0\u65b9\u5f0f\u4e3a\uff0c\u652f\u6301\u70ed\u52a0\u8f7d\u7684\u63d2\u4ef6\u673a\u5236\uff08 debugtalk.py \uff09\uff0c\u53ef\u4ee5\u5728 YAML/JSON \u4e2d\u8c03\u7528 Python \u51fd\u6570\u3002 \u5177\u4f53\u5730\u505a\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u540c\u7ea7\u6216\u5176\u7236\u7ea7\u76ee\u5f55\u4e2d\u521b\u5efa\u4e00\u4e2a debugtalk.py \u6587\u4ef6\uff0c\u7136\u540e\u5728\u5176\u4e2d\u5b9a\u4e49\u76f8\u5173\u7684\u51fd\u6570\u548c\u53d8\u91cf\u3002 \u4f8b\u5982\uff0c\u9488\u5bf9 device_sn \u7684\u968f\u673a\u5b57\u7b26\u4e32\u751f\u6210\u529f\u80fd\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a gen_random_string \u51fd\u6570\uff1b\u9488\u5bf9 sign \u7684\u7b7e\u540d\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a get_sign \u51fd\u6570\u3002 import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" def gen_random_string ( str_len ): random_char_list = [] for _ in range ( str_len ): random_char = random . choice ( string . ascii_letters + string . digits ) random_char_list . append ( random_char ) random_string = '' . join ( random_char_list ) return random_string def get_sign ( * args ): content = '' . join ( args ) . encode ( 'ascii' ) sign_key = SECRET_KEY . encode ( 'ascii' ) sign = hmac . new ( sign_key , content , hashlib . sha1 ) . hexdigest () return sign \u7136\u540e\uff0c\u6211\u4eec\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u5bf9\u5b9a\u4e49\u7684\u51fd\u6570\u8fdb\u884c\u8c03\u7528\uff0c\u5bf9\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4e86\u3002\u5f15\u7528\u53d8\u91cf\u7684\u65b9\u5f0f\u4ecd\u7136\u4e0e\u524d\u9762\u8bb2\u7684\u4e00\u6837\uff0c\u91c7\u7528 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\uff1b\u8c03\u7528\u51fd\u6570\u7684\u65b9\u5f0f\u4e3a ${func($var)} \u3002 \u4f8b\u5982\uff0c\u751f\u6210 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u5e76\u8d4b\u503c\u7ed9 device_sn \u7684\u4ee3\u7801\u4e3a\uff1a \"variables\" : [ { \"device_sn\" : \"${gen_random_string(15)}\" } ] \u4f7f\u7528 $user_agent\u3001$device_sn\u3001$os_platform\u3001$app_version \u6839\u636e\u7b7e\u540d\u7b97\u6cd5\u751f\u6210 sign \u503c\u7684\u4ee3\u7801\u4e3a\uff1a \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } \u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u4e0a\u8ff0\u8c03\u6574\u540e\uff0c\u53e6\u5b58\u4e3a demo-quickstart-6.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-6.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002 \u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8 \u00b6 \u8bf7\u786e\u4fdd\u4f60\u4f7f\u7528\u7684 HttpRunner \u7248\u672c\u53f7\u4e0d\u4f4e\u4e8e 2.0.0 \u5728 demo-quickstart-6.yml \u4e2d\uff0cuser_id \u4ecd\u7136\u662f\u5199\u6b7b\u7684\u503c\uff0c\u5047\u5982\u6211\u4eec\u9700\u8981\u521b\u5efa user_id \u4e3a 1001\uff5e1004 \u7684\u7528\u6237\uff0c\u90a3\u6211\u4eec\u53ea\u80fd\u4e0d\u65ad\u5730\u53bb\u4fee\u6539 user_id\uff0c\u7136\u540e\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u91cd\u590d\u64cd\u4f5c 4 \u6b21\uff1f\u6216\u8005\u6211\u4eec\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u5c06\u521b\u5efa\u7528\u6237\u7684 test \u590d\u5236 4 \u4efd\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u4efd\u91cc\u9762\u5206\u522b\u4f7f\u7528\u4e0d\u540c\u7684 user_id \uff1f \u5f88\u663e\u7136\uff0c\u4e0d\u7ba1\u662f\u91c7\u7528\u4e0a\u8ff0\u54ea\u79cd\u65b9\u5f0f\uff0c\u90fd\u4f1a\u5f88\u7e41\u7410\uff0c\u5e76\u4e14\u4e5f\u65e0\u6cd5\u5e94\u5bf9\u7075\u6d3b\u591a\u53d8\u7684\u6d4b\u8bd5\u9700\u6c42\u3002 \u9488\u5bf9\u8fd9\u7c7b\u9700\u6c42\uff0cHttpRunner \u652f\u6301\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u7684\u529f\u80fd\u3002 \u5728 HttpRunner \u4e2d\uff0c\u82e5\u8981\u91c7\u7528\u6570\u636e\u9a71\u52a8\u7684\u65b9\u5f0f\u6765\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\uff0c\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u5f15\u7528\uff0c\u5e76\u4f7f\u7528 parameters \u5173\u952e\u5b57\u5b9a\u4e49\u53c2\u6570\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u521b\u5efa\u7528\u6237\u7684\u63a5\u53e3\u4e2d\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\uff0c\u53c2\u6570\u5316\u5217\u8868\u4e3a 1001\uff5e1004\uff0c\u5e76\u4e14\u53d6\u503c\u65b9\u5f0f\u4e3a\u987a\u5e8f\u53d6\u503c\uff0c\u90a3\u4e48\u6700\u7b80\u5355\u7684\u63cf\u8ff0\u65b9\u5f0f\u5c31\u662f\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u3002\u5177\u4f53\u7684\u7f16\u5199\u65b9\u5f0f\u4e3a\uff0c\u65b0\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u573a\u666f\u6587\u4ef6 demo-quickstart-7.yml \uff08\u5bf9\u5e94\u7684 JSON \u683c\u5f0f\uff1a demo-quickstart-7.json \uff09\uff0c\u5185\u5bb9\u5982\u4e0b\u6240\u793a\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u4ec5\u9700\u5982\u4e0a\u914d\u7f6e\uff0c\u9488\u5bf9 user_id \u7684\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u5c31\u5b8c\u6210\u4e86\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u60c5\u51b5\u5982\u4e0b\u6240\u793a\uff1a \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002 \u5173\u4e8e\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u8fd9\u91cc\u53ea\u63cf\u8ff0\u4e86\u6700\u7b80\u5355\u7684\u573a\u666f\u548c\u4f7f\u7528\u65b9\u5f0f\uff0c\u5982\u9700\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u8fdb\u4e00\u6b65\u9605\u8bfb \u300a\u6570\u636e\u9a71\u52a8\u4f7f\u7528\u624b\u518c\u300b \u3002 \u67e5\u770b\u6d4b\u8bd5\u62a5\u544a \u00b6 \u5728\u6bcf\u6b21\u4f7f\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u5747\u4f1a\u751f\u6210\u4e00\u4efd HTML \u683c\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\u3002\u62a5\u544a\u6587\u4ef6\u4f4d\u4e8e reports \u76ee\u5f55\u4e0b\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5f00\u59cb\u8fd0\u884c\u65f6\u95f4\u3002 \u4f8b\u5982\uff0c\u5728\u8fd0\u884c\u5b8c demo-quickstart-1.json \u540e\uff0c\u5c06\u751f\u6210\u5982\u4e0b\u5f62\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\uff1a \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u62a5\u544a\u300b \u90e8\u5206\u3002 \u603b\u7ed3 \u00b6 \u5230\u6b64\u4e3a\u6b62\uff0cHttpRunner \u7684\u6838\u5fc3\u529f\u80fd\u5c31\u4ecb\u7ecd\u5b8c\u4e86\uff0c\u638c\u63e1\u672c\u6587\u4e2d\u7684\u529f\u80fd\u7279\u6027\uff0c\u8db3\u4ee5\u5e2e\u52a9\u4f60\u5e94\u5bf9\u65e5\u5e38\u9879\u76ee\u5de5\u4f5c\u4e2d\u81f3\u5c11 80% \u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\u3002 \u5f53\u7136\uff0cHttpRunner \u4e0d\u6b62\u4e8e\u6b64\uff0c\u5982\u9700\u6316\u6398 HttpRunner \u7684\u66f4\u591a\u7279\u6027\uff0c\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\uff0c\u53ef\u7ee7\u7eed\u9605\u8bfb\u540e\u7eed\u6587\u6863\u3002","title":"\u5feb\u901f\u4e0a\u624b"},{"location":"quickstart/#_1","text":"\u8be5\u6848\u4f8b\u4f5c\u4e3a\u88ab\u6d4b\u670d\u52a1\uff0c\u4e3b\u8981\u6709\u4e24\u7c7b\u63a5\u53e3\uff1a \u6743\u9650\u6821\u9a8c\uff0c\u83b7\u53d6 token \u652f\u6301 CRUD \u64cd\u4f5c\u7684 RESTful APIs\uff0c\u6240\u6709\u63a5\u53e3\u7684\u8bf7\u6c42\u5934\u57df\u4e2d\u90fd\u5fc5\u987b\u5305\u542b\u6709\u6548\u7684 token \u6848\u4f8b\u7684\u5b9e\u73b0\u5f62\u5f0f\u4e3a flask \u5e94\u7528\u670d\u52a1\uff08 api_server.py \uff09\uff0c\u542f\u52a8\u65b9\u5f0f\u5982\u4e0b\uff1a $ export FLASK_APP=docs/data/api_server.py $ export FLASK_ENV=development $ flask run * Serving Flask app \"docs/data/api_server.py\" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 989-476-348 \u670d\u52a1\u542f\u52a8\u6210\u529f\u540e\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u5bf9\u5176\u8fdb\u884c\u6d4b\u8bd5\u4e86\u3002","title":"\u6848\u4f8b\u4ecb\u7ecd"},{"location":"quickstart/#_2","text":"","title":"\u6d4b\u8bd5\u51c6\u5907"},{"location":"quickstart/#_3","text":"\u5728\u5f00\u59cb\u6d4b\u8bd5\u4e4b\u524d\uff0c\u6211\u4eec\u9700\u8981\u5148\u4e86\u89e3\u63a5\u53e3\u7684\u8bf7\u6c42\u548c\u54cd\u5e94\u7ec6\u8282\uff0c\u800c\u6700\u4f73\u7684\u65b9\u5f0f\u5c31\u662f\u91c7\u7528 Charles Proxy \u6216\u8005 Fiddler \u8fd9\u7c7b\u7f51\u7edc\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u5206\u6790\u3002 \u4f8b\u5982\uff0c\u5728\u672c\u6848\u4f8b\u4e2d\uff0c\u6211\u4eec\u5148\u8fdb\u884c\u6743\u9650\u6821\u9a8c\uff0c\u7136\u540e\u6210\u529f\u521b\u5efa\u4e00\u4e2a\u7528\u6237\uff0c\u5bf9\u5e94\u7684\u7f51\u7edc\u6293\u5305\u5185\u5bb9\u5982\u4e0b\u56fe\u6240\u793a\uff1a \u901a\u8fc7\u6293\u5305\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5177\u4f53\u7684\u63a5\u53e3\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684URL\u3001Method\u3001headers\u3001\u53c2\u6570\u548c\u54cd\u5e94\u5185\u5bb9\u7b49\u5185\u5bb9\uff0c\u57fa\u4e8e\u8fd9\u4e9b\u4fe1\u606f\uff0c\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u7f16\u5199\u6d4b\u8bd5\u7528\u4f8b\u4e86\u3002","title":"\u6293\u5305\u5206\u6790"},{"location":"quickstart/#_4","text":"\u4e3a\u4e86\u7b80\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7f16\u5199\u5de5\u4f5c\uff0cHttpRunner \u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u7684\u529f\u80fd\u3002 \u9996\u5148\uff0c\u9700\u8981\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\uff0c\u5047\u8bbe\u5bfc\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo-quickstart.har \u3002 \u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c\u5982\u4e0b\u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo-quickstart.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\uff0c\u52a0\u4e0a -2y \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002\u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002\u5173\u4e8e har2case \u7684\u8be6\u7ec6\u4f7f\u7528\u8bf4\u660e\uff0c\u8bf7\u67e5\u770b \u300a\u5f55\u5236\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u300b \u3002 \u7ecf\u8fc7\u8f6c\u6362\uff0c\u5728\u6e90 demo-quickstart.har \u6587\u4ef6\u7684\u540c\u7ea7\u76ee\u5f55\u4e0b\u751f\u6210\u4e86\u76f8\u540c\u6587\u4ef6\u540d\u79f0\u7684 YAML \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6 demo-quickstart.yml \uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a - config : name : testcase description variables : {} - test : name : /api/get-token request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : 2.8.6 device_sn : FwgRiO7CNA50DSU os_platform : ios json : sign : 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98 method : POST url : http://127.0.0.1:5000/api/get-token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.token , baNLX1zhFYP11Seb ] - test : name : /api/users/1000 request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 device_sn : FwgRiO7CNA50DSU token : baNLX1zhFYP11Seb json : name : user1 password : '123456' method : POST url : http://127.0.0.1:5000/api/users/1000 validate : - eq : [ status_code , 201 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] - eq : [ content.msg , user created successfully. ] \u73b0\u5728\u6211\u4eec\u53ea\u9700\u8981\u77e5\u9053\u5982\u4e0b\u51e0\u70b9\uff1a \u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e3a\u4e00\u4e2a list of dict \u7ed3\u6784\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 config \u4e3a\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b test \u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4f5c\u7528\u57df\u4ec5\u9650\u4e8e\u672c\u8eab \u5982\u4e0a\u4fbf\u662f HttpRunner \u6d4b\u8bd5\u7528\u4f8b\u7684\u57fa\u672c\u7ed3\u6784\u3002 \u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u63cf\u8ff0\u300b \u3002","title":"\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b"},{"location":"quickstart/#_5","text":"\u6d4b\u8bd5\u7528\u4f8b\u5c31\u7eea\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f00\u59cb\u8c03\u8bd5\u8fd0\u884c\u4e86\u3002 \u4e3a\u4e86\u6f14\u793a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8fed\u4ee3\u4f18\u5316\u8fc7\u7a0b\uff0c\u6211\u4eec\u5148\u5c06 demo-quickstart.json \u91cd\u547d\u540d\u4e3a demo-quickstart-0.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-0.yml \uff09\u3002 \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u547d\u4ee4\u4e3a hrun \uff0c\u540e\u9762\u76f4\u63a5\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\u5373\u53ef\u3002 $ hrun docs/data/demo-quickstart-0.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.26 ms, response_length: 46 bytes ERROR validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/get-token method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios'} json: {'sign': '9c0c7e51c91ae963c833a4ccbab8d683c4a90c98'} verify: True ====== response details ====== status_code: 200 headers: {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": true, \"token\": \"tXGuSQgOCVXcltkz\"}' F /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:43:55 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0000_000 (httprunner.api.TestSequense) /api/get-token ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: content.token equals baNLX1zhFYP11Seb(str) ==> fail tXGuSQgOCVXcltkz(str) equals baNLX1zhFYP11Seb(str) ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.026s FAILED (failures=2) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513835.html \u975e\u5e38\u4e0d\u5e78\uff0c\u4e24\u4e2a\u63a5\u53e3\u7684\u6d4b\u8bd5\u7528\u4f8b\u5747\u8fd0\u884c\u5931\u8d25\u4e86\u3002","title":"\u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b"},{"location":"quickstart/#_6","text":"\u4ece\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u62a5\u9519\u4fe1\u606f\u548c\u5806\u6808\u4fe1\u606f\uff08Traceback\uff09\u53ef\u4ee5\u770b\u51fa\uff0c\u7b2c\u4e00\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u83b7\u53d6\u7684 token \u4e0e\u9884\u671f\u503c\u4e0d\u4e00\u81f4\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u5931\u8d25\u7684\u539f\u56e0\u662f\u8bf7\u6c42\u6743\u9650\u6821\u9a8c\u5931\u8d25\uff08403\uff09\u3002 \u63a5\u4e0b\u6765\u6211\u4eec\u5c06\u9010\u6b65\u8fdb\u884c\u8fdb\u884c\u4f18\u5316\u3002","title":"\u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b"},{"location":"quickstart/#_7","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c har2case \u751f\u6210\u7528\u4f8b\u65f6\uff0c\u82e5 HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u4f1a\u5c06\u7b2c\u4e00\u5c42\u7ea7\u4e2d\u7684\u6240\u6709 key-value \u8f6c\u6362\u4e3a validator\u3002 \u4f8b\u5982\u4e0a\u9762\u7684\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u751f\u6210\u7684 validator \u4e3a\uff1a \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]} ] \u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u5c31\u4f1a\u5bf9\u4e0a\u9762\u7684\u5404\u4e2a\u9879\u8fdb\u884c\u6821\u9a8c\u3002 \u95ee\u9898\u5728\u4e8e\uff0c\u8bf7\u6c42 /api/get-token \u63a5\u53e3\u65f6\uff0c\u6bcf\u6b21\u751f\u6210\u7684 token \u90fd\u4f1a\u662f\u4e0d\u540c\u7684\uff0c\u56e0\u6b64\u5c06\u751f\u6210\u7684 token \u4f5c\u4e3a\u6821\u9a8c\u9879\u7684\u8bdd\uff0c\u6821\u9a8c\u81ea\u7136\u5c31\u65e0\u6cd5\u901a\u8fc7\u4e86\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u5e94\u8be5\u53bb\u6389\u8fd9\u7c7b\u52a8\u6001\u53d8\u5316\u7684\u503c\u3002 \u53bb\u9664\u8be5\u9879\u540e\uff0c\u5c06\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-1.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-1.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-1.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 6.61 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 ERROR 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) ERROR validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) ERROR validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ERROR ******************************** DETAILED REQUEST & RESPONSE ******************************** ====== request details ====== url: http://127.0.0.1:5000/api/users/1000 method: POST headers: {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 'device_sn': 'FwgRiO7CNA50DSU', 'token': 'baNLX1zhFYP11Seb'} json: {'name': 'user1', 'password': '123456'} verify: True ====== response details ====== status_code: 403 headers: {'Content-Type': 'application/json', 'Content-Length': '50', 'Server': 'Werkzeug/0.14.1 Python/3.7.0', 'Date': 'Sat, 26 Jan 2019 14:45:34 GMT'} body: '{\"success\": false, \"msg\": \"Authorization failed!\"}' F ====================================================================== FAIL: test_0001_000 (httprunner.api.TestSequense) /api/users/1000 ---------------------------------------------------------------------- Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 54, in test test_runner.run_test(test_dict) httprunner.exceptions.ValidationFailure: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/Users/debugtalk/.pyenv/versions/3.6-dev/lib/python3.6/site-packages/httprunner/api.py\", line 56, in test self.fail(str(ex)) AssertionError: validate: status_code equals 201(int) ==> fail 403(int) equals 201(int) validate: content.success equals True(bool) ==> fail False(bool) equals True(bool) validate: content.msg equals user created successfully.(str) ==> fail Authorization failed!(str) equals user created successfully.(str) ---------------------------------------------------------------------- Ran 2 tests in 0.018s FAILED (failures=1) INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548513934.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5df2\u7ecf\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u7b2c\u4e8c\u4e2a\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u5931\u8d25\uff08403\uff09\uff0c\u8fd8\u662f\u56e0\u4e3a\u6743\u9650\u6821\u9a8c\u7684\u539f\u56e0\u3002","title":"\u8c03\u6574\u6821\u9a8c\u5668"},{"location":"quickstart/#_8","text":"\u6211\u4eec\u7ee7\u7eed\u67e5\u770b demo-quickstart-1.json \uff0c\u4f1a\u53d1\u73b0\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42 headers \u4e2d\u7684 token \u4ecd\u7136\u662f\u786c\u7f16\u7801\u7684\uff0c\u5373\u6293\u5305\u65f6\u83b7\u53d6\u5230\u7684\u503c\u3002\u5728\u6211\u4eec\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\u8fd9\u4e2a token \u5df2\u7ecf\u5931\u6548\u4e86\uff0c\u6240\u4ee5\u4f1a\u51fa\u73b0 403 \u6743\u9650\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u6b63\u786e\u7684\u505a\u6cd5\u662f\uff0c\u6211\u4eec\u5e94\u8be5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u5148\u52a8\u6001\u83b7\u53d6\u5230\u7b2c\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 token\uff0c\u7136\u540e\u5728\u540e\u7eed\u6d4b\u8bd5\u6b65\u9aa4\u7684\u8bf7\u6c42\u4e2d\u4f7f\u7528\u524d\u9762\u83b7\u53d6\u5230\u7684 token\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53c2\u6570\u63d0\u53d6\uff08 extract \uff09\u548c\u53c2\u6570\u5f15\u7528\u7684\u529f\u80fd\uff08 $var \uff09\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\uff0c\u82e5\u9700\u8981\u4ece\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5219\u53ef\u4f7f\u7528 extract \u5173\u952e\u5b57\u3002extract \u7684\u5217\u8868\u4e2d\u53ef\u6307\u5b9a\u4e00\u4e2a\u6216\u591a\u4e2a\u9700\u8981\u63d0\u53d6\u7684\u53c2\u6570\u3002 \u5728\u63d0\u53d6\u53c2\u6570\u65f6\uff0c\u5f53 HTTP \u7684\u8bf7\u6c42\u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u683c\u5f0f\uff0c\u5219\u53ef\u4ee5\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u9010\u7ea7\u5f80\u4e0b\u83b7\u53d6\u5230\u53c2\u6570\u503c\uff1b\u54cd\u5e94\u7ed3\u679c\u7684\u6574\u4f53\u5185\u5bb9\u5f15\u7528\u65b9\u5f0f\u4e3a content \u6216\u8005 body\u3002 \u4f8b\u5982\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3 /api/get-token \u7684\u54cd\u5e94\u7ed3\u679c\u4e3a\uff1a { \"success\" : true , \"token\" : \"ZQkYhbaQ6q8UFFNE\" } \u90a3\u4e48\u8981\u83b7\u53d6\u5230 token \u53c2\u6570\uff0c\u5c31\u53ef\u4ee5\u4f7f\u7528 content.token \u7684\u65b9\u5f0f\uff1b\u5177\u4f53\u7684\u5199\u6cd5\u5982\u4e0b\uff1a \"extract\" : [ { \"token\" : \"content.token\" } ] \u5176\u4e2d\uff0ctoken \u4f5c\u4e3a\u63d0\u53d6\u540e\u7684\u53c2\u6570\u540d\u79f0\uff0c\u53ef\u4ee5\u5728\u540e\u7eed\u4f7f\u7528 $token \u8fdb\u884c\u5f15\u7528\u3002 \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" , \"Content-Type\" : \"application/json\" } \u4fee\u6539\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-2.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-2.yml \uff09\u3002 \u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff1a $ hrun docs/data/demo-quickstart-2.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.32 ms, response_length: 46 bytes . /api/users/1000 INFO POST http://127.0.0.1:5000/api/users/1000 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548514191.html \u7ecf\u8fc7\u4fee\u6539\uff0c\u7b2c\u4e8c\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e5f\u8fd0\u884c\u6210\u529f\u4e86\u3002","title":"\u53c2\u6570\u5173\u8054"},{"location":"quickstart/#base_url","text":"\u867d\u7136\u6d4b\u8bd5\u6b65\u9aa4\u8fd0\u884c\u90fd\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4ecd\u7136\u6709\u7ee7\u7eed\u4f18\u5316\u7684\u5730\u65b9\u3002 \u7ee7\u7eed\u67e5\u770b demo-quickstart-2.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u7684 URL \u4e2d\uff0c\u90fd\u91c7\u7528\u7684\u662f\u5b8c\u6574\u7684\u63cf\u8ff0\uff08host+path\uff09\uff0c\u4f46\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u540c\u4e00\u4e2a\u7528\u4f8b\u4e2d\u7684 host \u90fd\u662f\u76f8\u540c\u7684\uff0c\u533a\u522b\u4ec5\u5728\u4e8e path \u90e8\u5206\u3002 \u56e0\u6b64\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09 URL \u7684 base_url \u62bd\u53d6\u51fa\u6765\uff0c\u653e\u5230\u5168\u5c40\u914d\u7f6e\u6a21\u5757\uff08config\uff09\u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u7684 URL \u53ea\u4fdd\u7559 PATH \u90e8\u5206\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 - test : name : get token request : url : /api/get-token \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-3.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-3.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002","title":"base_url"},{"location":"quickstart/#_9","text":"\u7ee7\u7eed\u67e5\u770b demo-quickstart-3.json \uff0c\u6211\u4eec\u4f1a\u53d1\u73b0\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b58\u5728\u8f83\u591a\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u4f8b\u5982 app_version\u3001device_sn\u3001os_platform\u3001user_id \u7b49\u3002 \u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u53ef\u4ee5\u4e0d\u7528\u4fee\u6539\u8fd9\u4e9b\u786c\u7f16\u7801\u7684\u53c2\u6570\uff0c\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u8fd0\u884c\u3002\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ef4\u62a4\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u540c\u4e00\u4e2a\u53c2\u6570\u503c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u51fa\u73b0\u591a\u6b21\uff0c\u90a3\u4e48\u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5c06\u8fd9\u4e9b\u53c2\u6570\u5b9a\u4e49\u4e3a\u53d8\u91cf\uff0c\u7136\u540e\u5728\u9700\u8981\u53c2\u6570\u7684\u5730\u65b9\u8fdb\u884c\u5f15\u7528\u3002 \u5728 HttpRunner \u4e2d\uff0c\u652f\u6301\u53d8\u91cf\u7533\u660e\uff08 variables \uff09\u548c\u5f15\u7528\uff08 $var \uff09\u7684\u673a\u5236\u3002\u5728 config \u548c test \u4e2d\u5747\u53ef\u4ee5\u901a\u8fc7 variables \u5173\u952e\u5b57\u5b9a\u4e49\u53d8\u91cf\uff0c\u7136\u540e\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u53ef\u4ee5\u901a\u8fc7 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\u5f15\u7528\u53d8\u91cf\u3002\u533a\u522b\u5728\u4e8e\uff0c\u5728 config \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4e3a\u5168\u5c40\u7684\uff0c\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6240\u6709\u5730\u65b9\u5747\u53ef\u4ee5\u5f15\u7528\uff1b\u5728 test \u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u4f5c\u7528\u57df\u4ec5\u5c40\u9650\u4e8e\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u3002 \u5bf9\u4e0a\u8ff0\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u786c\u7f16\u7801\u7684\u53c2\u6570\u8fdb\u884c\u53d8\u91cf\u7533\u660e\u548c\u5f15\u7528\u8c03\u6574\u540e\uff0c\u65b0\u7684\u6d4b\u8bd5\u7528\u4f8b\u53e6\u5b58\u4e3a demo-quickstart-4.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-4.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002","title":"\u53d8\u91cf\u7684\u7533\u660e\u548c\u5f15\u7528"},{"location":"quickstart/#_10","text":"\u67e5\u770b demo-quickstart-4.json \u53ef\u4ee5\u770b\u51fa\uff0c\u4e24\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u90fd\u5b9a\u4e49\u4e86 device_sn\u3002\u9488\u5bf9\u8fd9\u7c7b\u516c\u5171\u7684\u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u5176\u7edf\u4e00\u5b9a\u4e49\u5728 config \u7684 variables \u4e2d\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5c31\u4e0d\u7528\u518d\u91cd\u590d\u5b9a\u4e49\u3002 - config : name : testcase description base_url : http://127.0.0.1:5000 variables : device_sn : FwgRiO7CNA50DSU \u8c03\u6574\u540e\u7684\u6d4b\u8bd5\u7528\u4f8b\u89c1 demo-quickstart-5.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-5.yml \uff09\u3002","title":"\u62bd\u53d6\u516c\u5171\u53d8\u91cf"},{"location":"quickstart/#_11","text":"\u5728 demo-quickstart-5.yml \u4e2d\uff0c\u53c2\u6570 device_sn \u4ee3\u8868\u7684\u662f\u8bbe\u5907\u7684 SN \u7f16\u7801\uff0c\u867d\u7136\u91c7\u7528\u786c\u7f16\u7801\u7684\u65b9\u5f0f\u6682\u65f6\u4e0d\u5f71\u54cd\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\uff0c\u4f46\u8fd9\u4e0e\u771f\u5b9e\u7684\u7528\u6237\u573a\u666f\u4e0d\u5927\u76f8\u7b26\u3002 \u5047\u8bbe device_sn \u7684\u683c\u5f0f\u4e3a 15 \u957f\u5ea6\u7684\u5b57\u7b26\u4e32\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u5728\u6bcf\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u7684\u65f6\u5019\uff0c\u9488\u5bf9 device_sn \u751f\u6210\u4e00\u4e2a 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u3002\b\u4e0e\u6b64\u540c\u65f6\uff0csign \u5b57\u6bb5\u662f\u6839\u636e headers \u4e2d\u7684\u5404\u4e2a\u5b57\u6bb5\u62fc\u63a5\u540e\u751f\u6210\u5f97\u5230\u7684 MD5 \u503c\uff0c\u56e0\u6b64\u5728 device_sn \u53d8\u52a8\u540e\uff0csign \u4e5f\u5e94\u8be5\u91cd\u65b0\u8fdb\u884c\u8ba1\u7b97\uff0c\u5426\u5219\u5c31\u4f1a\u518d\u6b21\u51fa\u73b0\u7b7e\u540d\u6821\u9a8c\u5931\u8d25\u7684\u95ee\u9898\u3002 \u7136\u800c\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u91c7\u7528 YAML/JSON \u683c\u5f0f\u8fdb\u884c\u63cf\u8ff0\u7684\uff0c\u5728\u6587\u672c\u683c\u5f0f\u4e2d\u5982\u4f55\u6267\u884c\u4ee3\u7801\u8fd0\u7b97\u5462\uff1f HttpRunner \u7684\u5b9e\u73b0\u65b9\u5f0f\u4e3a\uff0c\u652f\u6301\u70ed\u52a0\u8f7d\u7684\u63d2\u4ef6\u673a\u5236\uff08 debugtalk.py \uff09\uff0c\u53ef\u4ee5\u5728 YAML/JSON \u4e2d\u8c03\u7528 Python \u51fd\u6570\u3002 \u5177\u4f53\u5730\u505a\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u540c\u7ea7\u6216\u5176\u7236\u7ea7\u76ee\u5f55\u4e2d\u521b\u5efa\u4e00\u4e2a debugtalk.py \u6587\u4ef6\uff0c\u7136\u540e\u5728\u5176\u4e2d\u5b9a\u4e49\u76f8\u5173\u7684\u51fd\u6570\u548c\u53d8\u91cf\u3002 \u4f8b\u5982\uff0c\u9488\u5bf9 device_sn \u7684\u968f\u673a\u5b57\u7b26\u4e32\u751f\u6210\u529f\u80fd\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a gen_random_string \u51fd\u6570\uff1b\u9488\u5bf9 sign \u7684\u7b7e\u540d\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a get_sign \u51fd\u6570\u3002 import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" def gen_random_string ( str_len ): random_char_list = [] for _ in range ( str_len ): random_char = random . choice ( string . ascii_letters + string . digits ) random_char_list . append ( random_char ) random_string = '' . join ( random_char_list ) return random_string def get_sign ( * args ): content = '' . join ( args ) . encode ( 'ascii' ) sign_key = SECRET_KEY . encode ( 'ascii' ) sign = hmac . new ( sign_key , content , hashlib . sha1 ) . hexdigest () return sign \u7136\u540e\uff0c\u6211\u4eec\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u5bf9\u5b9a\u4e49\u7684\u51fd\u6570\u8fdb\u884c\u8c03\u7528\uff0c\u5bf9\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4e86\u3002\u5f15\u7528\u53d8\u91cf\u7684\u65b9\u5f0f\u4ecd\u7136\u4e0e\u524d\u9762\u8bb2\u7684\u4e00\u6837\uff0c\u91c7\u7528 $ + \u53d8\u91cf\u540d\u79f0 \u7684\u65b9\u5f0f\uff1b\u8c03\u7528\u51fd\u6570\u7684\u65b9\u5f0f\u4e3a ${func($var)} \u3002 \u4f8b\u5982\uff0c\u751f\u6210 15 \u4f4d\u957f\u5ea6\u7684\u968f\u673a\u5b57\u7b26\u4e32\u5e76\u8d4b\u503c\u7ed9 device_sn \u7684\u4ee3\u7801\u4e3a\uff1a \"variables\" : [ { \"device_sn\" : \"${gen_random_string(15)}\" } ] \u4f7f\u7528 $user_agent\u3001$device_sn\u3001$os_platform\u3001$app_version \u6839\u636e\u7b7e\u540d\u7b97\u6cd5\u751f\u6210 sign \u503c\u7684\u4ee3\u7801\u4e3a\uff1a \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } \u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u4e0a\u8ff0\u8c03\u6574\u540e\uff0c\u53e6\u5b58\u4e3a demo-quickstart-6.json \uff08\u5bf9\u5e94\u7684 YAML \u683c\u5f0f\uff1a demo-quickstart-6.yml \uff09\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6240\u6709\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4ecd\u7136\u8fd0\u884c\u6210\u529f\u3002","title":"\u5b9e\u73b0\u52a8\u6001\u8fd0\u7b97\u903b\u8f91"},{"location":"quickstart/#_12","text":"\u8bf7\u786e\u4fdd\u4f60\u4f7f\u7528\u7684 HttpRunner \u7248\u672c\u53f7\u4e0d\u4f4e\u4e8e 2.0.0 \u5728 demo-quickstart-6.yml \u4e2d\uff0cuser_id \u4ecd\u7136\u662f\u5199\u6b7b\u7684\u503c\uff0c\u5047\u5982\u6211\u4eec\u9700\u8981\u521b\u5efa user_id \u4e3a 1001\uff5e1004 \u7684\u7528\u6237\uff0c\u90a3\u6211\u4eec\u53ea\u80fd\u4e0d\u65ad\u5730\u53bb\u4fee\u6539 user_id\uff0c\u7136\u540e\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u91cd\u590d\u64cd\u4f5c 4 \u6b21\uff1f\u6216\u8005\u6211\u4eec\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u5c06\u521b\u5efa\u7528\u6237\u7684 test \u590d\u5236 4 \u4efd\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u4efd\u91cc\u9762\u5206\u522b\u4f7f\u7528\u4e0d\u540c\u7684 user_id \uff1f \u5f88\u663e\u7136\uff0c\u4e0d\u7ba1\u662f\u91c7\u7528\u4e0a\u8ff0\u54ea\u79cd\u65b9\u5f0f\uff0c\u90fd\u4f1a\u5f88\u7e41\u7410\uff0c\u5e76\u4e14\u4e5f\u65e0\u6cd5\u5e94\u5bf9\u7075\u6d3b\u591a\u53d8\u7684\u6d4b\u8bd5\u9700\u6c42\u3002 \u9488\u5bf9\u8fd9\u7c7b\u9700\u6c42\uff0cHttpRunner \u652f\u6301\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u7684\u529f\u80fd\u3002 \u5728 HttpRunner \u4e2d\uff0c\u82e5\u8981\u91c7\u7528\u6570\u636e\u9a71\u52a8\u7684\u65b9\u5f0f\u6765\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\uff0c\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u5f15\u7528\uff0c\u5e76\u4f7f\u7528 parameters \u5173\u952e\u5b57\u5b9a\u4e49\u53c2\u6570\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u521b\u5efa\u7528\u6237\u7684\u63a5\u53e3\u4e2d\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\uff0c\u53c2\u6570\u5316\u5217\u8868\u4e3a 1001\uff5e1004\uff0c\u5e76\u4e14\u53d6\u503c\u65b9\u5f0f\u4e3a\u987a\u5e8f\u53d6\u503c\uff0c\u90a3\u4e48\u6700\u7b80\u5355\u7684\u63cf\u8ff0\u65b9\u5f0f\u5c31\u662f\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u3002\u5177\u4f53\u7684\u7f16\u5199\u65b9\u5f0f\u4e3a\uff0c\u65b0\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u573a\u666f\u6587\u4ef6 demo-quickstart-7.yml \uff08\u5bf9\u5e94\u7684 JSON \u683c\u5f0f\uff1a demo-quickstart-7.json \uff09\uff0c\u5185\u5bb9\u5982\u4e0b\u6240\u793a\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u4ec5\u9700\u5982\u4e0a\u914d\u7f6e\uff0c\u9488\u5bf9 user_id \u7684\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u5c31\u5b8c\u6210\u4e86\u3002 \u91cd\u542f flask \u5e94\u7528\u670d\u52a1\u540e\u518d\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\uff0c\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u60c5\u51b5\u5982\u4e0b\u6240\u793a\uff1a \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002 \u5173\u4e8e\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u8fd9\u91cc\u53ea\u63cf\u8ff0\u4e86\u6700\u7b80\u5355\u7684\u573a\u666f\u548c\u4f7f\u7528\u65b9\u5f0f\uff0c\u5982\u9700\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u8fdb\u4e00\u6b65\u9605\u8bfb \u300a\u6570\u636e\u9a71\u52a8\u4f7f\u7528\u624b\u518c\u300b \u3002","title":"\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8"},{"location":"quickstart/#_13","text":"\u5728\u6bcf\u6b21\u4f7f\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u5747\u4f1a\u751f\u6210\u4e00\u4efd HTML \u683c\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\u3002\u62a5\u544a\u6587\u4ef6\u4f4d\u4e8e reports \u76ee\u5f55\u4e0b\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5f00\u59cb\u8fd0\u884c\u65f6\u95f4\u3002 \u4f8b\u5982\uff0c\u5728\u8fd0\u884c\u5b8c demo-quickstart-1.json \u540e\uff0c\u5c06\u751f\u6210\u5982\u4e0b\u5f62\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\uff1a \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u300a\u6d4b\u8bd5\u62a5\u544a\u300b \u90e8\u5206\u3002","title":"\u67e5\u770b\u6d4b\u8bd5\u62a5\u544a"},{"location":"quickstart/#_14","text":"\u5230\u6b64\u4e3a\u6b62\uff0cHttpRunner \u7684\u6838\u5fc3\u529f\u80fd\u5c31\u4ecb\u7ecd\u5b8c\u4e86\uff0c\u638c\u63e1\u672c\u6587\u4e2d\u7684\u529f\u80fd\u7279\u6027\uff0c\u8db3\u4ee5\u5e2e\u52a9\u4f60\u5e94\u5bf9\u65e5\u5e38\u9879\u76ee\u5de5\u4f5c\u4e2d\u81f3\u5c11 80% \u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\u3002 \u5f53\u7136\uff0cHttpRunner \u4e0d\u6b62\u4e8e\u6b64\uff0c\u5982\u9700\u6316\u6398 HttpRunner \u7684\u66f4\u591a\u7279\u6027\uff0c\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u9700\u6c42\uff0c\u53ef\u7ee7\u7eed\u9605\u8bfb\u540e\u7eed\u6587\u6863\u3002","title":"\u603b\u7ed3"},{"location":"related-docs/","text":"\u5f00\u53d1\u7b14\u8bb0 \u00b6 DebugTalk \u6f14\u8bb2 \u00b6 MTSC 2018 : \u300a\u5927\u7586\u4e92\u8054\u7f51\u7684\u4e00\u7ad9\u5f0f\u81ea\u52a8\u5316\u6d4b\u8bd5\u89e3\u51b3\u65b9\u6848\uff08\u57fa\u4e8eHttpRunner\uff09\u300b PyCon China 2018 : \u300a\u501f\u52a9 Python \u5f00\u6e90\u751f\u6001\u6253\u9020\u4f01\u4e1a\u7ea7\u81ea\u52a8\u5316\u6d4b\u8bd5\u6846\u67b6\uff08HttpRunner\uff09\u300b MTSC 2019 : \u300aHttpRunner 2.0 \u6280\u672f\u67b6\u6784\u4e0e\u63a5\u53e3\u6d4b\u8bd5\u5e94\u7528\u300b","title":"\u76f8\u5173\u8d44\u6599"},{"location":"related-docs/#_1","text":"DebugTalk","title":"\u5f00\u53d1\u7b14\u8bb0"},{"location":"related-docs/#_2","text":"MTSC 2018 : \u300a\u5927\u7586\u4e92\u8054\u7f51\u7684\u4e00\u7ad9\u5f0f\u81ea\u52a8\u5316\u6d4b\u8bd5\u89e3\u51b3\u65b9\u6848\uff08\u57fa\u4e8eHttpRunner\uff09\u300b PyCon China 2018 : \u300a\u501f\u52a9 Python \u5f00\u6e90\u751f\u6001\u6253\u9020\u4f01\u4e1a\u7ea7\u81ea\u52a8\u5316\u6d4b\u8bd5\u6846\u67b6\uff08HttpRunner\uff09\u300b MTSC 2019 : \u300aHttpRunner 2.0 \u6280\u672f\u67b6\u6784\u4e0e\u63a5\u53e3\u6d4b\u8bd5\u5e94\u7528\u300b","title":"\u6f14\u8bb2"},{"location":"sponsors/","text":"\u8d5e\u52a9\u5546 \u00b6 \u611f\u8c22\u5404\u4f4d\u5bf9 HttpRunner \u7684\u8d5e\u52a9\u652f\u6301\uff01 \u91d1\u724c\u8d5e\u52a9\u5546\uff08Gold Sponsor\uff09 \u00b6 \u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662 \u662f\u7531\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u4e0e\u77e5\u540d\u8f6f\u4ef6\u6d4b\u8bd5\u793e\u533a TesterHome \u5408\u4f5c\u7684\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\u3002\u7531 BAT \u4e00\u7ebf \u6d4b\u8bd5\u5927\u5496\u6267\u6559 \uff0c\u63d0\u4f9b \u5b9e\u6218\u9a71\u52a8 \u7684\u63a5\u53e3\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u79fb\u52a8\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u6027\u80fd\u6d4b\u8bd5\u3001\u6301\u7eed\u96c6\u6210\u4e0e DevOps \u7b49\u6280\u672f\u57f9\u8bad\uff0c\u4ee5\u53ca\u6d4b\u8bd5\u5f00\u53d1\u4f18\u79c0\u4eba\u624d\u5185\u63a8\u670d\u52a1\u3002 \u70b9\u51fb\u5b66\u4e60! \u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662\u662f HttpRunner \u7684\u9996\u5bb6\u91d1\u724c\u8d5e\u52a9\u5546\u3002 \u6210\u4e3a\u8d5e\u52a9\u5546 \u00b6 \u5982\u679c\u4f60\u6240\u5728\u7684\u516c\u53f8\u6216\u4e2a\u4eba\u4e5f\u60f3\u5bf9 HttpRunner \u8fdb\u884c\u8d5e\u52a9\uff0c\u53ef\u53c2\u8003\u5982\u4e0b\u65b9\u6848\uff0c\u5177\u4f53\u53ef\u8054\u7cfb \u9879\u76ee\u4f5c\u8005 \u3002 \u7b49\u7ea7 \u91d1\u724c\u8d5e\u52a9\u5546 \uff08Gold Sponsor\uff09 \u94f6\u724c\u8d5e\u52a9\u5546 \uff08Silver Sponsor\uff09 \u4e2a\u4eba\u8d5e\u8d4f \u91d1\u989d \uffe510000/\u5e74 \uffe55000/\u5e74 \u4efb\u610f \u6743\u76ca \u516c\u53f8 logo\uff08\u5927\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 150 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u516c\u53f8 logo\uff08\u4e2d\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 50 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u4e2a\u4eba ID \u548c\u94fe\u63a5\u5c55\u793a\u5728 sponsors.md","title":"\u8d5e\u52a9\u5546"},{"location":"sponsors/#_1","text":"\u611f\u8c22\u5404\u4f4d\u5bf9 HttpRunner \u7684\u8d5e\u52a9\u652f\u6301\uff01","title":"\u8d5e\u52a9\u5546"},{"location":"sponsors/#gold-sponsor","text":"\u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662 \u662f\u7531\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u4e0e\u77e5\u540d\u8f6f\u4ef6\u6d4b\u8bd5\u793e\u533a TesterHome \u5408\u4f5c\u7684\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\u3002\u7531 BAT \u4e00\u7ebf \u6d4b\u8bd5\u5927\u5496\u6267\u6559 \uff0c\u63d0\u4f9b \u5b9e\u6218\u9a71\u52a8 \u7684\u63a5\u53e3\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u79fb\u52a8\u81ea\u52a8\u5316\u6d4b\u8bd5\u3001\u6027\u80fd\u6d4b\u8bd5\u3001\u6301\u7eed\u96c6\u6210\u4e0e DevOps \u7b49\u6280\u672f\u57f9\u8bad\uff0c\u4ee5\u53ca\u6d4b\u8bd5\u5f00\u53d1\u4f18\u79c0\u4eba\u624d\u5185\u63a8\u670d\u52a1\u3002 \u70b9\u51fb\u5b66\u4e60! \u970d\u683c\u6c83\u5179\u6d4b\u8bd5\u5b66\u9662\u662f HttpRunner \u7684\u9996\u5bb6\u91d1\u724c\u8d5e\u52a9\u5546\u3002","title":"\u91d1\u724c\u8d5e\u52a9\u5546\uff08Gold Sponsor\uff09"},{"location":"sponsors/#_2","text":"\u5982\u679c\u4f60\u6240\u5728\u7684\u516c\u53f8\u6216\u4e2a\u4eba\u4e5f\u60f3\u5bf9 HttpRunner \u8fdb\u884c\u8d5e\u52a9\uff0c\u53ef\u53c2\u8003\u5982\u4e0b\u65b9\u6848\uff0c\u5177\u4f53\u53ef\u8054\u7cfb \u9879\u76ee\u4f5c\u8005 \u3002 \u7b49\u7ea7 \u91d1\u724c\u8d5e\u52a9\u5546 \uff08Gold Sponsor\uff09 \u94f6\u724c\u8d5e\u52a9\u5546 \uff08Silver Sponsor\uff09 \u4e2a\u4eba\u8d5e\u8d4f \u91d1\u989d \uffe510000/\u5e74 \uffe55000/\u5e74 \u4efb\u610f \u6743\u76ca \u516c\u53f8 logo\uff08\u5927\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 150 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u516c\u53f8 logo\uff08\u4e2d\uff09\u548c\u94fe\u63a5\u5c55\u793a\u5728 README.md 50 \u5b57\u7684\u5ba3\u4f20\u6587\u6848 \u4e2a\u4eba ID \u548c\u94fe\u63a5\u5c55\u793a\u5728 sponsors.md","title":"\u6210\u4e3a\u8d5e\u52a9\u5546"},{"location":"concept/nominal/","text":"\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u00b6 \u4ece 2.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u5f00\u59cb\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u7684\u5b9a\u4e49\u8fdb\u884c\u8fdb\u4e00\u6b65\u7684\u660e\u786e\uff0c\u53c2\u8003 wiki \u4e0a\u7684\u63cf\u8ff0\u3002 A test case is a specification of the inputs, execution conditions, testing procedure, and expected results that define a single test to be executed to achieve a particular software testing objective, such as to exercise a particular program path or to verify compliance with a specific requirement. \u6982\u62ec\u4e0b\u6765\uff0c\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u4e3a\u4e86\u6d4b\u8bd5\u67d0\u4e2a\u7279\u5b9a\u7684\u529f\u80fd\u903b\u8f91\u800c\u7cbe\u5fc3\u8bbe\u8ba1\u7684\uff0c\u5e76\u4e14\u81f3\u5c11\u5305\u542b\u5982\u4e0b\u51e0\u70b9\uff1a \u660e\u786e\u7684\u6d4b\u8bd5\u76ee\u7684\uff08achieve a particular software testing objective\uff09 \u660e\u786e\u7684\u8f93\u5165\uff08inputs\uff09 \u660e\u786e\u7684\u8fd0\u884c\u73af\u5883\uff08execution conditions\uff09 \u660e\u786e\u7684\u6d4b\u8bd5\u6b65\u9aa4\u63cf\u8ff0\uff08testing procedure\uff09 \u660e\u786e\u7684\u9884\u671f\u7ed3\u679c\uff08expected results\uff09 \u5bf9\u5e94\u5730\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u65b9\u5f0f\u8fdb\u884c\u5982\u4e0b\u8bbe\u8ba1\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684\uff1b\u5728 HttpRunner \u4e2d\uff0c\u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u3002 \u6d4b\u8bd5\u7528\u4f8b\u5305\u542b \u6d4b\u8bd5\u811a\u672c \u548c \u6d4b\u8bd5\u6570\u636e \u4e24\u90e8\u5206\uff1a \u6d4b\u8bd5\u7528\u4f8b = \u6d4b\u8bd5\u811a\u672c + \u6d4b\u8bd5\u6570\u636e \u6d4b\u8bd5\u811a\u672c \u91cd\u70b9\u662f\u63cf\u8ff0\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u529f\u80fd\u903b\u8f91 \uff0c\u5305\u62ec\u9884\u7f6e\u6761\u4ef6\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u9884\u671f\u7ed3\u679c\u7b49\uff0c\u5e76\u4e14\u53ef\u4ee5\u7ed3\u5408\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\u5b9e\u73b0\u590d\u6742\u7684\u8fd0\u7b97\u903b\u8f91\uff1b\u53ef\u4ee5\u5c06 \u6d4b\u8bd5\u811a\u672c \u7406\u89e3\u4e3a\u7f16\u7a0b\u8bed\u8a00\u4e2d\u7684 \u7c7b\uff08class\uff09 \uff1b \u6d4b\u8bd5\u6570\u636e \u91cd\u70b9\u662f\u5bf9\u5e94\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u6570\u636e\u903b\u8f91 \uff0c\u53ef\u4ee5\u7406\u89e3\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u6570\u636e\uff1b \u6d4b\u8bd5\u6570\u636e \u548c \u6d4b\u8bd5\u811a\u672c \u5206\u79bb\u540e\uff0c\u5c31\u53ef\u4ee5\u6bd4\u8f83\u65b9\u4fbf\u5730\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u6d4b\u8bd5\uff0c\u901a\u8fc7\u5bf9\u6d4b\u8bd5\u811a\u672c\u4f20\u5165\u4e00\u7ec4\u6570\u636e\uff0c\u5b9e\u73b0\u540c\u4e00\u4e1a\u52a1\u529f\u80fd\u5728\u4e0d\u540c\u6570\u636e\u903b\u8f91\u4e0b\u7684\u6d4b\u8bd5\u9a8c\u8bc1\u3002 \u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09 \u00b6 \u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u800c\u5bf9\u4e8e\u63a5\u53e3\u6d4b\u8bd5\u6765\u8bf4\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5e94\u8be5\u5c31\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0\u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09 \u00b6 \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\u3002 \u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u600e\u4e48\u529e\uff0c\u4f8b\u5982\u767b\u5f55\u529f\u80fd\u548c\u4e0b\u5355\u529f\u80fd\u3002\u6b63\u786e\u7684\u505a\u6cd5\u5e94\u8be5\u662f\uff0c\u5728\u4e0b\u5355\u6d4b\u8bd5\u7528\u4f8b\u7684\u524d\u7f6e\u6b65\u9aa4\u4e2d\u6267\u884c\u767b\u5f55\u64cd\u4f5c\u3002 - config : name : order product - test : name : login testcase : testcases/login.yml - test : name : add to cart api : api/add_cart.yml - test : name : make order api : api/make_order.yml \u6d4b\u8bd5\u573a\u666f \u00b6 \u6d4b\u8bd5\u573a\u666f \u548c \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f\u540c\u4e00\u6982\u5ff5\uff0c\u90fd\u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\u3002 \u63a5\u53e3 \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u53c2\u6570 \u53d8\u91cf \u6d4b\u8bd5\u811a\u672c\uff08YAML/JSON\uff09 debugtalk.py \u73af\u5883\u53d8\u91cf \u9879\u76ee\u6839\u76ee\u5f55 \u00b6","title":"\u540d\u8bcd\u89e3\u91ca"},{"location":"concept/nominal/#testcase","text":"\u4ece 2.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u5f00\u59cb\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u7684\u5b9a\u4e49\u8fdb\u884c\u8fdb\u4e00\u6b65\u7684\u660e\u786e\uff0c\u53c2\u8003 wiki \u4e0a\u7684\u63cf\u8ff0\u3002 A test case is a specification of the inputs, execution conditions, testing procedure, and expected results that define a single test to be executed to achieve a particular software testing objective, such as to exercise a particular program path or to verify compliance with a specific requirement. \u6982\u62ec\u4e0b\u6765\uff0c\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u4e3a\u4e86\u6d4b\u8bd5\u67d0\u4e2a\u7279\u5b9a\u7684\u529f\u80fd\u903b\u8f91\u800c\u7cbe\u5fc3\u8bbe\u8ba1\u7684\uff0c\u5e76\u4e14\u81f3\u5c11\u5305\u542b\u5982\u4e0b\u51e0\u70b9\uff1a \u660e\u786e\u7684\u6d4b\u8bd5\u76ee\u7684\uff08achieve a particular software testing objective\uff09 \u660e\u786e\u7684\u8f93\u5165\uff08inputs\uff09 \u660e\u786e\u7684\u8fd0\u884c\u73af\u5883\uff08execution conditions\uff09 \u660e\u786e\u7684\u6d4b\u8bd5\u6b65\u9aa4\u63cf\u8ff0\uff08testing procedure\uff09 \u660e\u786e\u7684\u9884\u671f\u7ed3\u679c\uff08expected results\uff09 \u5bf9\u5e94\u5730\uff0cHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u63cf\u8ff0\u65b9\u5f0f\u8fdb\u884c\u5982\u4e0b\u8bbe\u8ba1\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684\uff1b\u5728 HttpRunner \u4e2d\uff0c\u6bcf\u4e2a YAML/JSON \u6587\u4ef6\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u3002 \u6d4b\u8bd5\u7528\u4f8b\u5305\u542b \u6d4b\u8bd5\u811a\u672c \u548c \u6d4b\u8bd5\u6570\u636e \u4e24\u90e8\u5206\uff1a \u6d4b\u8bd5\u7528\u4f8b = \u6d4b\u8bd5\u811a\u672c + \u6d4b\u8bd5\u6570\u636e \u6d4b\u8bd5\u811a\u672c \u91cd\u70b9\u662f\u63cf\u8ff0\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u529f\u80fd\u903b\u8f91 \uff0c\u5305\u62ec\u9884\u7f6e\u6761\u4ef6\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u9884\u671f\u7ed3\u679c\u7b49\uff0c\u5e76\u4e14\u53ef\u4ee5\u7ed3\u5408\u8f85\u52a9\u51fd\u6570\uff08debugtalk.py\uff09\u5b9e\u73b0\u590d\u6742\u7684\u8fd0\u7b97\u903b\u8f91\uff1b\u53ef\u4ee5\u5c06 \u6d4b\u8bd5\u811a\u672c \u7406\u89e3\u4e3a\u7f16\u7a0b\u8bed\u8a00\u4e2d\u7684 \u7c7b\uff08class\uff09 \uff1b \u6d4b\u8bd5\u6570\u636e \u91cd\u70b9\u662f\u5bf9\u5e94\u6d4b\u8bd5\u7684 \u4e1a\u52a1\u6570\u636e\u903b\u8f91 \uff0c\u53ef\u4ee5\u7406\u89e3\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u6570\u636e\uff1b \u6d4b\u8bd5\u6570\u636e \u548c \u6d4b\u8bd5\u811a\u672c \u5206\u79bb\u540e\uff0c\u5c31\u53ef\u4ee5\u6bd4\u8f83\u65b9\u4fbf\u5730\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u6d4b\u8bd5\uff0c\u901a\u8fc7\u5bf9\u6d4b\u8bd5\u811a\u672c\u4f20\u5165\u4e00\u7ec4\u6570\u636e\uff0c\u5b9e\u73b0\u540c\u4e00\u4e1a\u52a1\u529f\u80fd\u5728\u4e0d\u540c\u6570\u636e\u903b\u8f91\u4e0b\u7684\u6d4b\u8bd5\u9a8c\u8bc1\u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09"},{"location":"concept/nominal/#teststep","text":"\u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u800c\u5bf9\u4e8e\u63a5\u53e3\u6d4b\u8bd5\u6765\u8bf4\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5e94\u8be5\u5c31\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0\u3002","title":"\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09"},{"location":"concept/nominal/#testsuite","text":"\u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\u3002 \u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u600e\u4e48\u529e\uff0c\u4f8b\u5982\u767b\u5f55\u529f\u80fd\u548c\u4e0b\u5355\u529f\u80fd\u3002\u6b63\u786e\u7684\u505a\u6cd5\u5e94\u8be5\u662f\uff0c\u5728\u4e0b\u5355\u6d4b\u8bd5\u7528\u4f8b\u7684\u524d\u7f6e\u6b65\u9aa4\u4e2d\u6267\u884c\u767b\u5f55\u64cd\u4f5c\u3002 - config : name : order product - test : name : login testcase : testcases/login.yml - test : name : add to cart api : api/add_cart.yml - test : name : make order api : api/make_order.yml","title":"\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09"},{"location":"concept/nominal/#_1","text":"\u6d4b\u8bd5\u573a\u666f \u548c \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u662f\u540c\u4e00\u6982\u5ff5\uff0c\u90fd\u662f \u6d4b\u8bd5\u7528\u4f8b \u7684 \u65e0\u5e8f \u96c6\u5408\u3002 \u63a5\u53e3 \u6d4b\u8bd5\u7528\u4f8b\u96c6 \u53c2\u6570 \u53d8\u91cf \u6d4b\u8bd5\u811a\u672c\uff08YAML/JSON\uff09 debugtalk.py \u73af\u5883\u53d8\u91cf","title":"\u6d4b\u8bd5\u573a\u666f"},{"location":"concept/nominal/#_2","text":"","title":"\u9879\u76ee\u6839\u76ee\u5f55"},{"location":"development/architecture/","text":"","title":"Pipline"},{"location":"development/dev-api/","text":"\u5f00\u53d1\u6269\u5c55 \u00b6 HttpRunner \u9664\u4e86\u4f5c\u4e3a\u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f5c\u4e3a\u8f6f\u4ef6\u5305\u96c6\u6210\u5230\u4f60\u81ea\u5df1\u7684\u9879\u76ee\u4e2d\u3002 \u7b80\u5355\u6765\u8bf4\uff0cHttpRunner \u63d0\u4f9b\u4e86\u8fd0\u884c YAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u7684\u80fd\u529b\uff0c\u5e76\u80fd\u8fd4\u56de\u8be6\u7ec6\u7684\u6d4b\u8bd5\u7ed3\u679c\u4fe1\u606f\u3002 HttpRunner class \u00b6 TL;DR \u00b6 HttpRunner \u4ee5 \u7c7b\uff08class\uff09 \u7684\u5f62\u5f0f\u5bf9\u5916\u63d0\u4f9b\u8c03\u7528\u652f\u6301\uff0c\u7c7b\u540d\b\u4e3a HttpRunner \u3002\u4f7f\u7528\u65b9\u5f0f\u5982\u4e0b\uff1a from httprunner.api import HttpRunner runner = HttpRunner ( failfast = True , save_tests = True , log_level = \"INFO\" , log_file = \"test.log\" ) summary = runner . run ( path_or_tests ) \u521d\u59cb\u5316\u53c2\u6570\u8bf4\u660e \u00b6 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u521d\u59cb\u5316 HttpRunner \u65f6\u7684\u53c2\u6570\u6709\u5982\u4e0b\u51e0\u4e2a\uff1a failfast \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u4e3a True \u65f6\uff0c\u6d4b\u8bd5\u5728\u9996\u6b21\u9047\u5230\u9519\u8bef\u6216\u5931\u8d25\u65f6\u4f1a\u505c\u6b62\u8fd0\u884c\uff1b\u9ed8\u8ba4\u503c\u4e3a False save_tests \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u4e3a True \u65f6\uff0c\u4f1a\u5c06\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u7684\u72b6\u6001\uff08loaded/parsed/summary\uff09\u4fdd\u5b58\u4e3a JSON \u6587\u4ef6\uff0c\u5b58\u50a8\u4e8e logs \u76ee\u5f55\u4e0b\uff1b\u9ed8\u8ba4\u4e3a False log_level \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u65e5\u5fd7\u7ea7\u522b\uff0c\u9ed8\u8ba4\u4e3a \"INFO\" log_file \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u65e5\u5fd7\u6587\u4ef6\u8def\u5f84\uff0c\u6307\u5b9a\u540e\u5c06\u540c\u65f6\u8f93\u51fa\u65e5\u5fd7\u6587\u4ef6\uff1b\u9ed8\u8ba4\u4e0d\u8f93\u51fa\u65e5\u5fd7\u6587\u4ef6 \b\u8c03\u7528\u65b9\u6cd5\u8bf4\u660e \u00b6 \u5728 HttpRunner \u4e2d\uff0c\u5bf9\u5916\u63d0\u4f9b\u4e86\u4e00\u4e2a run \u65b9\u6cd5\uff0c\u7528\u4e8e\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u3002 run \u65b9\u6cd5\u6709\u4e09\u4e2a\u53c2\u6570\uff1a path_or_tests \uff08\u5fc5\u4f20\uff09: \u6307\u5b9a\u8981\u8fd0\u884c\u7684\u6d4b\u8bd5\u7528\u4f8b\uff1b\u652f\u6301\u4f20\u5165\u4e24\u7c7b\u53c2\u6570 str: YAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84 dict: \u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53 dot_env_path \uff08\u53ef\u9009\uff09: \u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u9ed8\u8ba4\u503c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e2d\u7684 .env \u6587\u4ef6 mapping \uff08\u53ef\u9009\uff09: \u53d8\u91cf\u6620\u5c04\uff0c\u53ef\u7528\u4e8e\u5bf9\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\u3002 \u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84 \u00b6 \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u652f\u6301\u4e09\u79cd\u5f62\u5f0f\uff1a YAML/JSON \u6587\u4ef6\u8def\u5f84\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u5305\u542b YAML/JSON \u6587\u4ef6\u7684\u6587\u4ef6\u5939\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u6587\u4ef6\u8def\u5f84\u548c\u6587\u4ef6\u5939\u8def\u5f84\u7684\u6df7\u5408\u60c5\u51b5\uff08list/set\uff09 # \u6587\u4ef6\u8def\u5f84 runner . run ( \"docs/data/demo-quickstart-2.yml\" ) # \u6587\u4ef6\u5939\u8def\u5f84 runner . run ( \"docs/data/\" ) # \u6df7\u5408\u60c5\u51b5 runner . run ([ \"docs/data/\" , \"files/demo-quickstart-2.yml\" ]) \u5982\u9700\u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u6216\u8005\u9700\u8981\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\uff0c\u5219\u53ef\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\u3002 # dot_env_path runner . run ( \"docs/data/demo-quickstart-2.yml\" , dot_env_path = \"/path/to/.env\" ) # mapping override_mapping = { \"device_sn\" : \"XXX\" } runner . run ( \"docs/data/demo-quickstart-2.yml\" , mapping = override_mapping ) \u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53 \u00b6 \u9664\u4e86\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\uff0c\u8fd8\u53ef\u4ee5\u76f4\u63a5\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u3002 \u4ee5 demo-quickstart-2.yml \u4e3a\u4f8b\uff0c\u5bf9\u5e94\u7684\u6570\u636e\u7ed3\u6784\u4f53\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { \"name\" : \"testcase description\" , \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" } }, \"variables\" : [], \"output\" : [ \"token\" ], \"path\" : \"/abs-path/to/demo-quickstart-2.yml\" , \"refs\" : { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } }, \"teststeps\" : [ { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" }, \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ] }, { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" }, \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [ { \"eq\" : [ \"status_code\" , 201 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]} ] } ] }, { ... } # another testcase ] \u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u65f6\uff0c\u652f\u6301\u4f20\u5165\u5355\u4e2a\u7ed3\u6784\u4f53\uff08dict\uff09\uff0c\u6216\u8005\u591a\u4e2a\u7ed3\u6784\u4f53\uff08list of dict\uff09\u3002 # \u8fd0\u884c\u5355\u4e2a\u7ed3\u6784\u4f53 runner . run ( testcase ) # \u8fd0\u884c\u591a\u4e2a\u7ed3\u6784\u4f53 runner . run ([ testcase1 , testcase2 ]) \u52a0\u8f7d debugtalk.py && .env \u00b6 \b\u901a\u8fc7\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\bHttpRunner \u4f1a\u81ea\u52a8\u4ee5\b\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u4e3a\u8d77\u70b9\uff0c\u5411\u4e0a\u641c\u7d22 debugtalk.py \u6587\u4ef6\uff0c\u5e76\u5c06 debugtalk.py \u6587\u4ef6\u6240\u5728\u7684\u6587\u4ef6\u76ee\u5f55\u4f5c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u3002 \u540c\u65f6\uff0cHttpRunner \u4f1a\u5728\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e0b\b\b\u641c\u7d22 .env \u6587\u4ef6\uff0c\u4ee5\u53ca api \u548c testcases \u6587\u4ef6\u5939\uff0c\u5e76\u81ea\u52a8\u8fdb\u884c\u52a0\u8f7d\u3002 \u6700\u7ec8\u52a0\u8f7d\u5f97\u5230\u7684\u5b58\u50a8\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } \u5176\u4e2d\uff0c env \u5bf9\u5e94\u7684\u662f .env \u6587\u4ef6\u4e2d\u7684\u73af\u5883\u53d8\u91cf\uff0c debugtalk \u5bf9\u5e94\u7684\u662f debugtalk.py \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u548c\u51fd\u6570\uff0c def-api \u5bf9\u5e94\u7684\u662f api \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u63a5\u53e3\u63cf\u8ff0\uff0c def-testcase \u5bf9\u5e94\u7684\u662f testcases \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u6d4b\u8bd5\u7528\u4f8b\u3002 \u901a\u8fc7\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u6267\u884c\u6d4b\u8bd5\u65f6\uff0c\u4f20\u5165\u7684\u6570\u636e\u5e94\u5305\u542b\u6240\u6709\u4fe1\u606f\uff0c\u5305\u62ec debugtalk.py \u3001 .env \u3001\u4f9d\u8d56\u7684 api \u548c \u6d4b\u8bd5\u7528\u4f8b\u7b49\uff1b\u56e0\u6b64\u4e5f\u65e0\u9700\u518d\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\uff0c\u6240\u6709\u4fe1\u606f\u90fd\u8981\u901a\u8fc7 refs \u4f20\u5165\u3002 \u8fd4\u56de\u8be6\u7ec6\u6d4b\u8bd5\u7ed3\u679c\u6570\u636e \u00b6 \u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u901a\u8fc7 run() \u65b9\u6cd5\u7684\u8fd4\u56de\u7ed3\u679c\u53ef\u83b7\u53d6\u8be6\u5c3d\u7684\u8fd0\u884c\u7ed3\u679c\u6570\u636e\u3002 summary = runner . run ( path_or_tests ) \u5176\u6570\u636e\u7ed3\u6784\u4e3a\uff1a { \"success\" : true , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"platform\" : { \"httprunner_version\" : \"1.5.14\" , \"python_version\" : \"CPython 3.6.5+\" , \"platform\" : \"Darwin-17.6.0-x86_64-i386-64bit\" }, \"details\" : [ { \"success\" : true , \"name\" : \"testcase description\" , \"base_url\" : \"\" , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"records\" : [ { \"name\" : \"/api/get-token\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" , \"Content-Length\" : \"52\" }, \"start_timestamp\" : 1538449655.944801 , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }, \"body\" : b' { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } ' }, \"response\" : { \"status_code\" : 200 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"46\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 46 , \"response_time_ms\" : 12.87 , \"elapsed_ms\" : 6.955 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"reason\" : \"OK\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"json\" : { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 200 , \"comparator\" : \"eq\" , \"check_value\" : 200 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" } ] } }, { \"name\" : \"/api/users/1000\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"CcQ7dBjZZbjIXRkG\" , \"Content-Length\" : \"39\" }, \"start_timestamp\" : 1538449655.958944 , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }, \"body\" : b' { \"name\" : \"user1\" , \"password\" : \"123456\" } ' }, \"response\" : { \"status_code\" : 201 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"54\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 54 , \"response_time_ms\" : 3.34 , \"elapsed_ms\" : 2.16 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"reason\" : \"CREATED\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"json\" : { \"success\" : true , \"msg\" : \"user created successfully.\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 201 , \"comparator\" : \"eq\" , \"check_value\" : 201 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" }, { \"check\" : \"content.msg\" , \"expect\" : \"user created successfully.\" , \"comparator\" : \"eq\" , \"check_value\" : \"user created successfully.\" , \"check_result\" : \"pass\" } ] } } ], \"in_out\" : { \"in\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"out\" : { \"token\" : \"CcQ7dBjZZbjIXRkG\" } } } ] } \u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a \u00b6 \u5982\u9700\u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u53ef\u8c03\u7528 report.render_html_report \u65b9\u6cd5\u3002 from httprunner import report report_path = report . render_html_report ( summary , report_template = \"/path/to/custom_report_template\" , report_dir = \"/path/to/reports_dir\" , report_file = \"/path/to/report_file_path\" ) render_html_report() \u7684\u53c2\u6570\u6709\u56db\u4e2a\uff1a summary\uff08\u5fc5\u4f20\uff09: \u6d4b\u8bd5\u8fd0\u884c\u7ed3\u679c\u6c47\u603b\u6570\u636e report_template\uff08\u53ef\u9009\uff09: \u6307\u5b9a\u81ea\u5b9a\u4e49\u7684 HTML \u62a5\u544a\u6a21\u677f\uff0c\u6a21\u677f\u5fc5\u987b\u91c7\u7528 Jinja2 \u7684\u683c\u5f0f report_dir\uff08\u53ef\u9009\uff09: \u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u6587\u4ef6\u5939\u8def\u5f84 report_file\uff08\u53ef\u9009\uff09: \u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u6587\u4ef6\u8def\u5f84\uff0c\u8be5\u53c2\u6570\u7684\u4f18\u5148\u7ea7\u9ad8\u4e8e report_dir \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u90e8\u5206\u3002","title":"\u57fa\u7840\u5e93\u8c03\u7528"},{"location":"development/dev-api/#_1","text":"HttpRunner \u9664\u4e86\u4f5c\u4e3a\u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f5c\u4e3a\u8f6f\u4ef6\u5305\u96c6\u6210\u5230\u4f60\u81ea\u5df1\u7684\u9879\u76ee\u4e2d\u3002 \u7b80\u5355\u6765\u8bf4\uff0cHttpRunner \u63d0\u4f9b\u4e86\u8fd0\u884c YAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u7684\u80fd\u529b\uff0c\u5e76\u80fd\u8fd4\u56de\u8be6\u7ec6\u7684\u6d4b\u8bd5\u7ed3\u679c\u4fe1\u606f\u3002","title":"\u5f00\u53d1\u6269\u5c55"},{"location":"development/dev-api/#httprunner-class","text":"","title":"HttpRunner class"},{"location":"development/dev-api/#tldr","text":"HttpRunner \u4ee5 \u7c7b\uff08class\uff09 \u7684\u5f62\u5f0f\u5bf9\u5916\u63d0\u4f9b\u8c03\u7528\u652f\u6301\uff0c\u7c7b\u540d\b\u4e3a HttpRunner \u3002\u4f7f\u7528\u65b9\u5f0f\u5982\u4e0b\uff1a from httprunner.api import HttpRunner runner = HttpRunner ( failfast = True , save_tests = True , log_level = \"INFO\" , log_file = \"test.log\" ) summary = runner . run ( path_or_tests )","title":"TL;DR"},{"location":"development/dev-api/#_2","text":"\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u521d\u59cb\u5316 HttpRunner \u65f6\u7684\u53c2\u6570\u6709\u5982\u4e0b\u51e0\u4e2a\uff1a failfast \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u4e3a True \u65f6\uff0c\u6d4b\u8bd5\u5728\u9996\u6b21\u9047\u5230\u9519\u8bef\u6216\u5931\u8d25\u65f6\u4f1a\u505c\u6b62\u8fd0\u884c\uff1b\u9ed8\u8ba4\u503c\u4e3a False save_tests \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u4e3a True \u65f6\uff0c\u4f1a\u5c06\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u7684\u72b6\u6001\uff08loaded/parsed/summary\uff09\u4fdd\u5b58\u4e3a JSON \u6587\u4ef6\uff0c\u5b58\u50a8\u4e8e logs \u76ee\u5f55\u4e0b\uff1b\u9ed8\u8ba4\u4e3a False log_level \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u65e5\u5fd7\u7ea7\u522b\uff0c\u9ed8\u8ba4\u4e3a \"INFO\" log_file \uff08\u53ef\u9009\uff09: \u8bbe\u7f6e\u65e5\u5fd7\u6587\u4ef6\u8def\u5f84\uff0c\u6307\u5b9a\u540e\u5c06\u540c\u65f6\u8f93\u51fa\u65e5\u5fd7\u6587\u4ef6\uff1b\u9ed8\u8ba4\u4e0d\u8f93\u51fa\u65e5\u5fd7\u6587\u4ef6","title":"\u521d\u59cb\u5316\u53c2\u6570\u8bf4\u660e"},{"location":"development/dev-api/#_3","text":"\u5728 HttpRunner \u4e2d\uff0c\u5bf9\u5916\u63d0\u4f9b\u4e86\u4e00\u4e2a run \u65b9\u6cd5\uff0c\u7528\u4e8e\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u3002 run \u65b9\u6cd5\u6709\u4e09\u4e2a\u53c2\u6570\uff1a path_or_tests \uff08\u5fc5\u4f20\uff09: \u6307\u5b9a\u8981\u8fd0\u884c\u7684\u6d4b\u8bd5\u7528\u4f8b\uff1b\u652f\u6301\u4f20\u5165\u4e24\u7c7b\u53c2\u6570 str: YAML/JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84 dict: \u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53 dot_env_path \uff08\u53ef\u9009\uff09: \u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u9ed8\u8ba4\u503c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e2d\u7684 .env \u6587\u4ef6 mapping \uff08\u53ef\u9009\uff09: \u53d8\u91cf\u6620\u5c04\uff0c\u53ef\u7528\u4e8e\u5bf9\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\u3002","title":"\b\u8c03\u7528\u65b9\u6cd5\u8bf4\u660e"},{"location":"development/dev-api/#_4","text":"\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u652f\u6301\u4e09\u79cd\u5f62\u5f0f\uff1a YAML/JSON \u6587\u4ef6\u8def\u5f84\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u5305\u542b YAML/JSON \u6587\u4ef6\u7684\u6587\u4ef6\u5939\uff0c\u652f\u6301\u7edd\u5bf9\u8def\u5f84\u548c\u76f8\u5bf9\u8def\u5f84 \u6587\u4ef6\u8def\u5f84\u548c\u6587\u4ef6\u5939\u8def\u5f84\u7684\u6df7\u5408\u60c5\u51b5\uff08list/set\uff09 # \u6587\u4ef6\u8def\u5f84 runner . run ( \"docs/data/demo-quickstart-2.yml\" ) # \u6587\u4ef6\u5939\u8def\u5f84 runner . run ( \"docs/data/\" ) # \u6df7\u5408\u60c5\u51b5 runner . run ([ \"docs/data/\" , \"files/demo-quickstart-2.yml\" ]) \u5982\u9700\u6307\u5b9a\u52a0\u8f7d\u73af\u5883\u53d8\u91cf\u6587\u4ef6\uff08.env\uff09\u7684\u8def\u5f84\uff0c\u6216\u8005\u9700\u8981\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u8986\u76d6\u66ff\u6362\uff0c\u5219\u53ef\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\u3002 # dot_env_path runner . run ( \"docs/data/demo-quickstart-2.yml\" , dot_env_path = \"/path/to/.env\" ) # mapping override_mapping = { \"device_sn\" : \"XXX\" } runner . run ( \"docs/data/demo-quickstart-2.yml\" , mapping = override_mapping )","title":"\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84"},{"location":"development/dev-api/#_5","text":"\u9664\u4e86\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\uff0c\u8fd8\u53ef\u4ee5\u76f4\u63a5\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u3002 \u4ee5 demo-quickstart-2.yml \u4e3a\u4f8b\uff0c\u5bf9\u5e94\u7684\u6570\u636e\u7ed3\u6784\u4f53\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { \"name\" : \"testcase description\" , \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" } }, \"variables\" : [], \"output\" : [ \"token\" ], \"path\" : \"/abs-path/to/demo-quickstart-2.yml\" , \"refs\" : { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } }, \"teststeps\" : [ { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" }, \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ] }, { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"$token\" }, \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [ { \"eq\" : [ \"status_code\" , 201 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]}, { \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]} ] } ] }, { ... } # another testcase ] \u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u65f6\uff0c\u652f\u6301\u4f20\u5165\u5355\u4e2a\u7ed3\u6784\u4f53\uff08dict\uff09\uff0c\u6216\u8005\u591a\u4e2a\u7ed3\u6784\u4f53\uff08list of dict\uff09\u3002 # \u8fd0\u884c\u5355\u4e2a\u7ed3\u6784\u4f53 runner . run ( testcase ) # \u8fd0\u884c\u591a\u4e2a\u7ed3\u6784\u4f53 runner . run ([ testcase1 , testcase2 ])","title":"\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53"},{"location":"development/dev-api/#debugtalkpy-env","text":"\b\u901a\u8fc7\u4f20\u5165\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u65f6\uff0c\bHttpRunner \u4f1a\u81ea\u52a8\u4ee5\b\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u4e3a\u8d77\u70b9\uff0c\u5411\u4e0a\u641c\u7d22 debugtalk.py \u6587\u4ef6\uff0c\u5e76\u5c06 debugtalk.py \u6587\u4ef6\u6240\u5728\u7684\u6587\u4ef6\u76ee\u5f55\u4f5c\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u3002 \u540c\u65f6\uff0cHttpRunner \u4f1a\u5728\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff08PWD\uff09\u4e0b\b\b\u641c\u7d22 .env \u6587\u4ef6\uff0c\u4ee5\u53ca api \u548c testcases \u6587\u4ef6\u5939\uff0c\u5e76\u81ea\u52a8\u8fdb\u884c\u52a0\u8f7d\u3002 \u6700\u7ec8\u52a0\u8f7d\u5f97\u5230\u7684\u5b58\u50a8\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a { \"env\" : {}, \"debugtalk\" : { \"variables\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"functions\" : { \"gen_random_string\" : , \"get_sign\" : , \"get_user_id\" : , \"get_account\" : , \"get_os_platform\" : } }, \"def-api\" : {}, \"def-testcase\" : {} } \u5176\u4e2d\uff0c env \u5bf9\u5e94\u7684\u662f .env \u6587\u4ef6\u4e2d\u7684\u73af\u5883\u53d8\u91cf\uff0c debugtalk \u5bf9\u5e94\u7684\u662f debugtalk.py \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u548c\u51fd\u6570\uff0c def-api \u5bf9\u5e94\u7684\u662f api \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u63a5\u53e3\u63cf\u8ff0\uff0c def-testcase \u5bf9\u5e94\u7684\u662f testcases \u6587\u4ef6\u5939\u4e0b\u5b9a\u4e49\u7684\u6d4b\u8bd5\u7528\u4f8b\u3002 \u901a\u8fc7\u4f20\u5165\u6807\u51c6\u7684\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784\u4f53\u6267\u884c\u6d4b\u8bd5\u65f6\uff0c\u4f20\u5165\u7684\u6570\u636e\u5e94\u5305\u542b\u6240\u6709\u4fe1\u606f\uff0c\u5305\u62ec debugtalk.py \u3001 .env \u3001\u4f9d\u8d56\u7684 api \u548c \u6d4b\u8bd5\u7528\u4f8b\u7b49\uff1b\u56e0\u6b64\u4e5f\u65e0\u9700\u518d\u4f7f\u7528 dot_env_path \u548c mapping \u53c2\u6570\uff0c\u6240\u6709\u4fe1\u606f\u90fd\u8981\u901a\u8fc7 refs \u4f20\u5165\u3002","title":"\u52a0\u8f7d debugtalk.py && .env"},{"location":"development/dev-api/#_6","text":"\u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u901a\u8fc7 run() \u65b9\u6cd5\u7684\u8fd4\u56de\u7ed3\u679c\u53ef\u83b7\u53d6\u8be6\u5c3d\u7684\u8fd0\u884c\u7ed3\u679c\u6570\u636e\u3002 summary = runner . run ( path_or_tests ) \u5176\u6570\u636e\u7ed3\u6784\u4e3a\uff1a { \"success\" : true , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"platform\" : { \"httprunner_version\" : \"1.5.14\" , \"python_version\" : \"CPython 3.6.5+\" , \"platform\" : \"Darwin-17.6.0-x86_64-i386-64bit\" }, \"details\" : [ { \"success\" : true , \"name\" : \"testcase description\" , \"base_url\" : \"\" , \"stat\" : { \"testsRun\" : 2 , \"failures\" : 0 , \"errors\" : 0 , \"skipped\" : 0 , \"expectedFailures\" : 0 , \"unexpectedSuccesses\" : 0 , \"successes\" : 2 }, \"time\" : { \"start_at\" : 1538449655.944404 , \"duration\" : 0.03181314468383789 }, \"records\" : [ { \"name\" : \"/api/get-token\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"app_version\" : \"2.8.6\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"os_platform\" : \"ios\" , \"user_agent\" : \"iOS/10.3\" , \"Content-Length\" : \"52\" }, \"start_timestamp\" : 1538449655.944801 , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }, \"body\" : b' { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" } ' }, \"response\" : { \"status_code\" : 200 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"46\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 46 , \"response_time_ms\" : 12.87 , \"elapsed_ms\" : 6.955 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"reason\" : \"OK\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } ' , \"json\" : { \"success\" : true , \"token\" : \"CcQ7dBjZZbjIXRkG\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 200 , \"comparator\" : \"eq\" , \"check_value\" : 200 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" } ] } }, { \"name\" : \"/api/users/1000\" , \"status\" : \"success\" , \"attachment\" : \"\" , \"meta_data\" : { \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"method\" : \"POST\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" , \"Accept-Encoding\" : \"gzip, deflate\" , \"Accept\" : \"*/*\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/json\" , \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"CcQ7dBjZZbjIXRkG\" , \"Content-Length\" : \"39\" }, \"start_timestamp\" : 1538449655.958944 , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }, \"body\" : b' { \"name\" : \"user1\" , \"password\" : \"123456\" } ' }, \"response\" : { \"status_code\" : 201 , \"headers\" : { \"Content-Type\" : \"application/json\" , \"Content-Length\" : \"54\" , \"Server\" : \"Werkzeug/0.14.1 Python/3.6.5+\" , \"Date\" : \"Tue, 02 Oct 2018 03:07:35 GMT\" }, \"content_size\" : 54 , \"response_time_ms\" : 3.34 , \"elapsed_ms\" : 2.16 , \"encoding\" : null , \"content\" : b' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"content_type\" : \"application/json\" , \"ok\" : true , \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"reason\" : \"CREATED\" , \"cookies\" : {}, \"text\" : ' { \"success\" : true , \"msg\" : \"user created successfully.\" } ' , \"json\" : { \"success\" : true , \"msg\" : \"user created successfully.\" } }, \"validators\" : [ { \"check\" : \"status_code\" , \"expect\" : 201 , \"comparator\" : \"eq\" , \"check_value\" : 201 , \"check_result\" : \"pass\" }, { \"check\" : \"headers.Content-Type\" , \"expect\" : \"application/json\" , \"comparator\" : \"eq\" , \"check_value\" : \"application/json\" , \"check_result\" : \"pass\" }, { \"check\" : \"content.success\" , \"expect\" : true , \"comparator\" : \"eq\" , \"check_value\" : true , \"check_result\" : \"pass\" }, { \"check\" : \"content.msg\" , \"expect\" : \"user created successfully.\" , \"comparator\" : \"eq\" , \"check_value\" : \"user created successfully.\" , \"check_result\" : \"pass\" } ] } } ], \"in_out\" : { \"in\" : { \"SECRET_KEY\" : \"DebugTalk\" }, \"out\" : { \"token\" : \"CcQ7dBjZZbjIXRkG\" } } } ] }","title":"\u8fd4\u56de\u8be6\u7ec6\u6d4b\u8bd5\u7ed3\u679c\u6570\u636e"},{"location":"development/dev-api/#html","text":"\u5982\u9700\u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u53ef\u8c03\u7528 report.render_html_report \u65b9\u6cd5\u3002 from httprunner import report report_path = report . render_html_report ( summary , report_template = \"/path/to/custom_report_template\" , report_dir = \"/path/to/reports_dir\" , report_file = \"/path/to/report_file_path\" ) render_html_report() \u7684\u53c2\u6570\u6709\u56db\u4e2a\uff1a summary\uff08\u5fc5\u4f20\uff09: \u6d4b\u8bd5\u8fd0\u884c\u7ed3\u679c\u6c47\u603b\u6570\u636e report_template\uff08\u53ef\u9009\uff09: \u6307\u5b9a\u81ea\u5b9a\u4e49\u7684 HTML \u62a5\u544a\u6a21\u677f\uff0c\u6a21\u677f\u5fc5\u987b\u91c7\u7528 Jinja2 \u7684\u683c\u5f0f report_dir\uff08\u53ef\u9009\uff09: \u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u6587\u4ef6\u5939\u8def\u5f84 report_file\uff08\u53ef\u9009\uff09: \u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u6587\u4ef6\u8def\u5f84\uff0c\u8be5\u53c2\u6570\u7684\u4f18\u5148\u7ea7\u9ad8\u4e8e report_dir \u5173\u4e8e\u6d4b\u8bd5\u62a5\u544a\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u8bf7\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u90e8\u5206\u3002","title":"\u751f\u6210 HTML \u6d4b\u8bd5\u62a5\u544a"},{"location":"examples/testerhome-login/","text":"\u6848\u4f8b\u4ecb\u7ecd \u00b6 \u901a\u8fc7\u63a5\u53e3\u81ea\u52a8\u5316\u5b9e\u73b0 TesterHome \u7684\u767b\u5f55\u9000\u51fa\u529f\u80fd\u3002 \u529f\u80fd\u63cf\u8ff0\uff1a \u8fdb\u5165 \u767b\u5f55\u9875\u9762 \u8f93\u5165\u8d26\u53f7\u548c\u5bc6\u7801 \u70b9\u51fb\u3010Sign In\u3011\u8fdb\u884c\u767b\u5f55 \u51c6\u5907\u5de5\u4f5c \u00b6 \u6293\u5305\u751f\u6210 HAR \u6587\u4ef6 \u00b6 \u5728\u6d4f\u89c8\u5668\u4e2d\u4eba\u5de5\u8fdb\u884c\u767b\u5f55\u64cd\u4f5c\uff0c\u540c\u65f6\u4f7f\u7528\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u3002\u6293\u5305\u65f6\u5efa\u8bae\u4f7f\u7528\u8fc7\u6ee4\u5668\uff08Filter\uff09\uff0c\u5e38\u7528\u7684\u505a\u6cd5\u662f\u91c7\u7528\u88ab\u6d4b\u7cfb\u7edf\u7684 host\uff0c\u5c06\u65e0\u5173\u8bf7\u6c42\u8fc7\u6ee4\u6389\u3002 \u9009\u62e9\u9700\u8981\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u7684\u8bf7\u6c42\uff0c\u5bfc\u51fa\u4e3a HTTP Archive (.har) \u683c\u5f0f\u7684\u6587\u4ef6\u3002 \u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e har2case \u547d\u4ee4\uff0c\u4f7f\u7528\u8be5\u547d\u4ee4\u53ef\u5c06 HAR \u6570\u636e\u5305\u8f6c\u6362\u4e3a HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/testerhome-login.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/testerhome-login.yml \u751f\u6210\u7684\u6d4b\u8bd5\u7528\u4f8b\u5185\u5bb9\u5982\u4e0b\uff1a \u70b9\u51fb\u67e5\u770b - config : name : testcase description variables : {} - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] - test : name : /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png request : headers : User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , image/png ] - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/javascript; charset=utf-8 ] - test : name : / request : headers : If-None-Match : W/\"bad62c68dac27b01151516aad5c7f0be\" Turbolinks-Referrer : https://testerhome.com/account/sign_in User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/ validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e hrun \u547d\u4ee4\uff0c\u8be5\u547d\u4ee4\u662f HttpRunner \u7684\u6838\u5fc3\u547d\u4ee4\uff0c\u7528\u4e8e\u8fd0\u884c HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u5c1d\u8bd5\u8fd0\u884c\u4e00\u6b21\uff0c\u5927\u591a\u6570\u60c5\u51b5\uff0c\u5982\u679c\u88ab\u6d4b\u573a\u666f\u4e2d\u4e0d\u5b58\u5728\u5173\u8054\u7684\u60c5\u51b5\uff0c\u662f\u53ef\u4ee5\u76f4\u63a5\u8fd0\u884c\u6210\u529f\u7684\u3002 $ hrun docs/data/testerhome-login.yml --failfast --log-level info INFO Start to run testcase: testcase description /account/sign_in INFO GET https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 189 .66 ms, response_length: 12584 bytes . /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO GET https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO status_code: 200 , response_time ( ms ) : 83 .98 ms, response_length: 15229 bytes . /account/sign_in INFO POST https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 172 .8 ms, response_length: 89 bytes . / INFO GET https://testerhome.com/ INFO status_code: 200 , response_time ( ms ) : 257 .41 ms, response_length: 52463 bytes . ---------------------------------------------------------------------- Ran 4 tests in 0 .722s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1555662601.html \u6bd4\u8f83\u5e78\u8fd0\uff0c\u811a\u672c\u5728\u6ca1\u6709\u505a\u4efb\u4f55\u4fee\u6539\u7684\u60c5\u51b5\u4e0b\u8fd0\u884c\u6210\u529f\u4e86\u3002 \u8c03\u8bd5 & \u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u867d\u7136\u811a\u672c\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ba1\u7406\u548c\u7ef4\u62a4\u811a\u672c\uff0c\u9700\u8981\u5bf9\u811a\u672c\u8fdb\u884c\u4f18\u5316\u8c03\u6574\u3002 \u5173\u8054\u5904\u7406 \u00b6 \u67e5\u770b\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\uff0c\u53ef\u4ee5\u770b\u5230\u5728\u53d1\u8d77\u767b\u5f55\u8bf7\u6c42\u65f6\u5305\u542b\u4e86 X-CSRF-Token \uff0c\u5982\u679c\u719f\u6089\u7f51\u7edc\u4fe1\u606f\u5b89\u5168\u7684\u57fa\u7840\u77e5\u8bc6\uff0c\u5c31\u4f1a\u8054\u60f3\u5230\u8be5\u5b57\u6bb5\u662f\u52a8\u6001\u53d8\u5316\u7684\uff0c\u6bcf\u6b21\u90fd\u662f\u5148\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u81f3\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u5728\u540e\u7eed\u53d1\u8d77\u8bf7\u6c42\u65f6\u9700\u8981\u643a\u5e26\u8be5\u5b57\u6bb5\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u867d\u7136\u5f53\u524d\u76f4\u63a5\u8fd0\u884c\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\u4e5f\u662f\u6210\u529f\u7684\uff0c\u4f46\u5f88\u6709\u53ef\u80fd\u5728\u8fc7\u4e86\u4e00\u6bb5\u65f6\u95f4\u540e\uff0c X-CSRF-Token \u5931\u6548\uff0c\u811a\u672c\u4e5f\u5c31\u65e0\u6cd5\u518d\u6210\u529f\u8fd0\u884c\u4e86\u3002\u56e0\u6b64\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\uff0c\u8be5\u5b57\u6bb5\u4e0d\u80fd\u5199\u6b7b\u4e3a\u6293\u5305\u65f6\u83b7\u53d6\u7684\u503c\uff0c\u800c\u662f\u8981\u6bcf\u6b21\u52a8\u6001\u5730\u4ece\u524d\u9762\u7684\u63a5\u53e3\u54cd\u5e94\u4e2d\u83b7\u53d6\u3002 \u90a3\u8981\u600e\u4e48\u786e\u5b9a\u8be5\u5b57\u6bb5\u662f\u5728\u4e4b\u524d\u7684\u54ea\u4e2a\u63a5\u53e3\u4e2d\u8fd4\u56de\u7684\u5462\uff1f \u64cd\u4f5c\u65b9\u5f0f\u4e5f\u5f88\u7b80\u5355\uff0c\u53ef\u4ee5\u5728\u6293\u5305\u5de5\u5177\u4e2d\u5bf9\u8be5\u5b57\u6bb5\u8fdb\u884c\u641c\u7d22\uff0c\u7279\u522b\u5730\uff0c\u641c\u7d22\u8303\u56f4\u9650\u5b9a\u4e3a\u54cd\u5e94\u5185\u5bb9\uff08Response Header\u3001Response Body\uff09\u3002 \u5373\u53ef\u641c\u7d22\u5f97\u5230\u8be5\u5b57\u6bb5\u662f\u5728\u54ea\u4e2a\u63a5\u53e3\u4e2d\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u503c\u5ba2\u6237\u7aef\u7684\u3002 \u6709\u65f6\u5019\u53ef\u80fd\u641c\u7d22\u4f1a\u5f97\u5230\u591a\u4e2a\u7ed3\u679c\uff0c\u90a3\u4e48\u5728\u786e\u5b9a\u662f\u4f7f\u7528\u54ea\u4e2a\u63a5\u53e3\u54cd\u5e94\u7684\u65f6\u5019\uff0c\u9075\u5faa\u4e24\u4e2a\u539f\u5219\u5373\u53ef\uff1a \u54cd\u5e94\u4e00\u5b9a\u662f\u51fa\u73b0\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d \u5982\u679c\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d\u5b58\u5728\u591a\u4e2a\u63a5\u53e3\u5747\u6709\u6b64\u8fd4\u56de\uff0c\u90a3\u4e48\u53d6\u6700\u9760\u8fd1\u5f53\u524d\u63a5\u53e3\u7684\u5373\u53ef \u901a\u8fc7\u524d\u9762\u7684\u641c\u7d22\u53ef\u77e5\uff0c X-CSRF-Token \u7684\u503c\u662f\u5728\u7b2c\u4e00\u4e2a\u63a5\u53e3\u4e2d\u54cd\u5e94\u8fd4\u56de\u7684\u3002 \u786e\u5b9a\u51fa\u5177\u4f53\u7684\u63a5\u53e3\u540e\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u4ece\u8be5\u63a5\u53e3\u4f7f\u7528 extract \u63d0\u53d6\u5bf9\u5e94\u7684\u5b57\u6bb5\uff0c\u7136\u540e\u5728\u540e\u7eed\u63a5\u53e3\u4e2d\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u3002 \u5728\u5f53\u524d\u6848\u4f8b\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a HTML \u9875\u9762\uff0c\u8981\u63d0\u53d6\u5b57\u6bb5\u53ef\u4ee5\u4f7f\u7528\u6b63\u5219\u5339\u914d\u7684\u65b9\u5f0f\u3002\u5177\u4f53\u7684\u505a\u6cd5\u5c31\u662f\u6307\u5b9a\u76ee\u6807\u5b57\u6bb5\u7684\u5de6\u53f3\u8fb9\u754c\uff0c\u76ee\u6807\u5b57\u6bb5\u4f7f\u7528 (.*) \u5339\u914d\u83b7\u53d6\u3002 - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in extract : X_CSRF_Token : validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u7136\u540e\uff0c\u5728\u540e\u7eed\u4f7f\u7528\u5230\u8be5\u5b57\u6bb5\u7684\u63a5\u53e3\u4e2d\uff0c\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u5373\u53ef\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : $X_CSRF_Token X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ]","title":"TesterHome \u767b\u5f55"},{"location":"examples/testerhome-login/#_1","text":"\u901a\u8fc7\u63a5\u53e3\u81ea\u52a8\u5316\u5b9e\u73b0 TesterHome \u7684\u767b\u5f55\u9000\u51fa\u529f\u80fd\u3002 \u529f\u80fd\u63cf\u8ff0\uff1a \u8fdb\u5165 \u767b\u5f55\u9875\u9762 \u8f93\u5165\u8d26\u53f7\u548c\u5bc6\u7801 \u70b9\u51fb\u3010Sign In\u3011\u8fdb\u884c\u767b\u5f55","title":"\u6848\u4f8b\u4ecb\u7ecd"},{"location":"examples/testerhome-login/#_2","text":"","title":"\u51c6\u5907\u5de5\u4f5c"},{"location":"examples/testerhome-login/#har","text":"\u5728\u6d4f\u89c8\u5668\u4e2d\u4eba\u5de5\u8fdb\u884c\u767b\u5f55\u64cd\u4f5c\uff0c\u540c\u65f6\u4f7f\u7528\u6293\u5305\u5de5\u5177\u8fdb\u884c\u6293\u5305\u3002\u6293\u5305\u65f6\u5efa\u8bae\u4f7f\u7528\u8fc7\u6ee4\u5668\uff08Filter\uff09\uff0c\u5e38\u7528\u7684\u505a\u6cd5\u662f\u91c7\u7528\u88ab\u6d4b\u7cfb\u7edf\u7684 host\uff0c\u5c06\u65e0\u5173\u8bf7\u6c42\u8fc7\u6ee4\u6389\u3002 \u9009\u62e9\u9700\u8981\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u7684\u8bf7\u6c42\uff0c\u5bfc\u51fa\u4e3a HTTP Archive (.har) \u683c\u5f0f\u7684\u6587\u4ef6\u3002","title":"\u6293\u5305\u751f\u6210 HAR \u6587\u4ef6"},{"location":"examples/testerhome-login/#_3","text":"\u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e har2case \u547d\u4ee4\uff0c\u4f7f\u7528\u8be5\u547d\u4ee4\u53ef\u5c06 HAR \u6570\u636e\u5305\u8f6c\u6362\u4e3a HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 $ har2case docs/data/testerhome-login.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/testerhome-login.yml \u751f\u6210\u7684\u6d4b\u8bd5\u7528\u4f8b\u5185\u5bb9\u5982\u4e0b\uff1a \u70b9\u51fb\u67e5\u770b - config : name : testcase description variables : {} - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] - test : name : /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png request : headers : User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , image/png ] - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/javascript; charset=utf-8 ] - test : name : / request : headers : If-None-Match : W/\"bad62c68dac27b01151516aad5c7f0be\" Turbolinks-Referrer : https://testerhome.com/account/sign_in User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/ validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ]","title":"\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b"},{"location":"examples/testerhome-login/#_4","text":"\u6210\u529f\u5b89\u88c5 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e hrun \u547d\u4ee4\uff0c\u8be5\u547d\u4ee4\u662f HttpRunner \u7684\u6838\u5fc3\u547d\u4ee4\uff0c\u7528\u4e8e\u8fd0\u884c HttpRunner \u652f\u6301\u7684 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u5c1d\u8bd5\u8fd0\u884c\u4e00\u6b21\uff0c\u5927\u591a\u6570\u60c5\u51b5\uff0c\u5982\u679c\u88ab\u6d4b\u573a\u666f\u4e2d\u4e0d\u5b58\u5728\u5173\u8054\u7684\u60c5\u51b5\uff0c\u662f\u53ef\u4ee5\u76f4\u63a5\u8fd0\u884c\u6210\u529f\u7684\u3002 $ hrun docs/data/testerhome-login.yml --failfast --log-level info INFO Start to run testcase: testcase description /account/sign_in INFO GET https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 189 .66 ms, response_length: 12584 bytes . /assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO GET https://testerhome.com/assets/big_logo-cd32144f74c18746f3dce33e1040e7dfe4c07c8e611e37f3868b1c16b5095da3.png INFO status_code: 200 , response_time ( ms ) : 83 .98 ms, response_length: 15229 bytes . /account/sign_in INFO POST https://testerhome.com/account/sign_in INFO status_code: 200 , response_time ( ms ) : 172 .8 ms, response_length: 89 bytes . / INFO GET https://testerhome.com/ INFO status_code: 200 , response_time ( ms ) : 257 .41 ms, response_length: 52463 bytes . ---------------------------------------------------------------------- Ran 4 tests in 0 .722s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1555662601.html \u6bd4\u8f83\u5e78\u8fd0\uff0c\u811a\u672c\u5728\u6ca1\u6709\u505a\u4efb\u4f55\u4fee\u6539\u7684\u60c5\u51b5\u4e0b\u8fd0\u884c\u6210\u529f\u4e86\u3002","title":"\u9996\u6b21\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b"},{"location":"examples/testerhome-login/#_5","text":"\u867d\u7136\u811a\u672c\u8fd0\u884c\u6210\u529f\u4e86\uff0c\u4f46\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u7ba1\u7406\u548c\u7ef4\u62a4\u811a\u672c\uff0c\u9700\u8981\u5bf9\u811a\u672c\u8fdb\u884c\u4f18\u5316\u8c03\u6574\u3002","title":"\u8c03\u8bd5 & \u4f18\u5316\u6d4b\u8bd5\u7528\u4f8b"},{"location":"examples/testerhome-login/#_6","text":"\u67e5\u770b\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\uff0c\u53ef\u4ee5\u770b\u5230\u5728\u53d1\u8d77\u767b\u5f55\u8bf7\u6c42\u65f6\u5305\u542b\u4e86 X-CSRF-Token \uff0c\u5982\u679c\u719f\u6089\u7f51\u7edc\u4fe1\u606f\u5b89\u5168\u7684\u57fa\u7840\u77e5\u8bc6\uff0c\u5c31\u4f1a\u8054\u60f3\u5230\u8be5\u5b57\u6bb5\u662f\u52a8\u6001\u53d8\u5316\u7684\uff0c\u6bcf\u6b21\u90fd\u662f\u5148\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u81f3\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u5728\u540e\u7eed\u53d1\u8d77\u8bf7\u6c42\u65f6\u9700\u8981\u643a\u5e26\u8be5\u5b57\u6bb5\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : 0zAKFDDPnNI2+Vwq/iwDPR9vo7KWobfNLAye4EaGBTlsSxMzTNf39lLF9z35f5mcROM7JgOP+azBCuDe84G+XA== X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u867d\u7136\u5f53\u524d\u76f4\u63a5\u8fd0\u884c\u5f55\u5236\u751f\u6210\u7684\u811a\u672c\u4e5f\u662f\u6210\u529f\u7684\uff0c\u4f46\u5f88\u6709\u53ef\u80fd\u5728\u8fc7\u4e86\u4e00\u6bb5\u65f6\u95f4\u540e\uff0c X-CSRF-Token \u5931\u6548\uff0c\u811a\u672c\u4e5f\u5c31\u65e0\u6cd5\u518d\u6210\u529f\u8fd0\u884c\u4e86\u3002\u56e0\u6b64\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\uff0c\u8be5\u5b57\u6bb5\u4e0d\u80fd\u5199\u6b7b\u4e3a\u6293\u5305\u65f6\u83b7\u53d6\u7684\u503c\uff0c\u800c\u662f\u8981\u6bcf\u6b21\u52a8\u6001\u5730\u4ece\u524d\u9762\u7684\u63a5\u53e3\u54cd\u5e94\u4e2d\u83b7\u53d6\u3002 \u90a3\u8981\u600e\u4e48\u786e\u5b9a\u8be5\u5b57\u6bb5\u662f\u5728\u4e4b\u524d\u7684\u54ea\u4e2a\u63a5\u53e3\u4e2d\u8fd4\u56de\u7684\u5462\uff1f \u64cd\u4f5c\u65b9\u5f0f\u4e5f\u5f88\u7b80\u5355\uff0c\u53ef\u4ee5\u5728\u6293\u5305\u5de5\u5177\u4e2d\u5bf9\u8be5\u5b57\u6bb5\u8fdb\u884c\u641c\u7d22\uff0c\u7279\u522b\u5730\uff0c\u641c\u7d22\u8303\u56f4\u9650\u5b9a\u4e3a\u54cd\u5e94\u5185\u5bb9\uff08Response Header\u3001Response Body\uff09\u3002 \u5373\u53ef\u641c\u7d22\u5f97\u5230\u8be5\u5b57\u6bb5\u662f\u5728\u54ea\u4e2a\u63a5\u53e3\u4e2d\u4ece\u670d\u52a1\u5668\u7aef\u8fd4\u56de\u503c\u5ba2\u6237\u7aef\u7684\u3002 \u6709\u65f6\u5019\u53ef\u80fd\u641c\u7d22\u4f1a\u5f97\u5230\u591a\u4e2a\u7ed3\u679c\uff0c\u90a3\u4e48\u5728\u786e\u5b9a\u662f\u4f7f\u7528\u54ea\u4e2a\u63a5\u53e3\u54cd\u5e94\u7684\u65f6\u5019\uff0c\u9075\u5faa\u4e24\u4e2a\u539f\u5219\u5373\u53ef\uff1a \u54cd\u5e94\u4e00\u5b9a\u662f\u51fa\u73b0\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d \u5982\u679c\u5728\u5f53\u524d\u63a5\u53e3\u4e4b\u524d\u5b58\u5728\u591a\u4e2a\u63a5\u53e3\u5747\u6709\u6b64\u8fd4\u56de\uff0c\u90a3\u4e48\u53d6\u6700\u9760\u8fd1\u5f53\u524d\u63a5\u53e3\u7684\u5373\u53ef \u901a\u8fc7\u524d\u9762\u7684\u641c\u7d22\u53ef\u77e5\uff0c X-CSRF-Token \u7684\u503c\u662f\u5728\u7b2c\u4e00\u4e2a\u63a5\u53e3\u4e2d\u54cd\u5e94\u8fd4\u56de\u7684\u3002 \u786e\u5b9a\u51fa\u5177\u4f53\u7684\u63a5\u53e3\u540e\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u811a\u672c\u4e2d\u4ece\u8be5\u63a5\u53e3\u4f7f\u7528 extract \u63d0\u53d6\u5bf9\u5e94\u7684\u5b57\u6bb5\uff0c\u7136\u540e\u5728\u540e\u7eed\u63a5\u53e3\u4e2d\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u3002 \u5728\u5f53\u524d\u6848\u4f8b\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u63a5\u53e3\u7684\u54cd\u5e94\u5185\u5bb9\u4e3a HTML \u9875\u9762\uff0c\u8981\u63d0\u53d6\u5b57\u6bb5\u53ef\u4ee5\u4f7f\u7528\u6b63\u5219\u5339\u914d\u7684\u65b9\u5f0f\u3002\u5177\u4f53\u7684\u505a\u6cd5\u5c31\u662f\u6307\u5b9a\u76ee\u6807\u5b57\u6bb5\u7684\u5de6\u53f3\u8fb9\u754c\uff0c\u76ee\u6807\u5b57\u6bb5\u4f7f\u7528 (.*) \u5339\u914d\u83b7\u53d6\u3002 - test : name : /account/sign_in request : headers : If-None-Match : W/\"bc9ae267fdcbd89bf1dfaea10dea2b0e\" User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 method : GET url : https://testerhome.com/account/sign_in extract : X_CSRF_Token : validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ] \u7136\u540e\uff0c\u5728\u540e\u7eed\u4f7f\u7528\u5230\u8be5\u5b57\u6bb5\u7684\u63a5\u53e3\u4e2d\uff0c\u5f15\u7528\u63d0\u53d6\u51fa\u7684\u5b57\u6bb5\u5373\u53ef\u3002 - test : name : /account/sign_in request : data : commit : Sign In user[login] : debugtalk user[password] : XXXXXXXX user[remember_me] : '1' utf8 : \u2713 headers : Content-Type : application/x-www-form-urlencoded; charset=UTF-8 User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 X-CSRF-Token : $X_CSRF_Token X-Requested-With : XMLHttpRequest method : POST url : https://testerhome.com/account/sign_in validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , text/html; charset=utf-8 ]","title":"\u5173\u8054\u5904\u7406"},{"location":"prepare/dot-env/","text":"\u73af\u5883\u53d8\u91cf\u7684\u4f5c\u7528 \u00b6 \u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u6709\u65f6\u9700\u8981\u501f\u52a9\u73af\u5883\u53d8\u91cf\u5b9e\u73b0\u67d0\u4e9b\u7279\u5b9a\u7684\u76ee\u7684\uff0c\u5e38\u89c1\u7684\u573a\u666f\u5305\u62ec\uff1a \u5207\u6362\u6d4b\u8bd5\u73af\u5883 \u5207\u6362\u6d4b\u8bd5\u914d\u7f6e \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u4ece \u4fe1\u606f\u5b89\u5168 \u7684\u89d2\u5ea6\u51fa\u53d1\uff09 \u8bbe\u7f6e\u73af\u5883\u53d8\u91cf \u00b6 \u5728\u7ec8\u7aef\u4e2d\u9884\u8bbe\u73af\u5883\u53d8\u91cf \u00b6 \u4f7f\u7528\u73af\u5883\u53d8\u91cf\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5728\u7cfb\u7edf\u4e2d\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u540d\u79f0\u548c\u503c\uff0c\u4f20\u7edf\u7684\u65b9\u5f0f\u4e3a\u4f7f\u7528 export \u547d\u4ee4\uff08Windows\u7cfb\u7edf\u4e2d\u4f7f\u7528 set \u547d\u4ee4\uff09\uff1a $ export UserName = admin $ echo $UserName admin $ export Password = 123456 $ echo $Password 123456 \u7136\u540e\uff0c\u5728\u7a0b\u5e8f\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u7cfb\u7edf\u4e2d\u7684\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u3002 $ python >>> import os >>> os.environ [ \"UserName\" ] 'admin' \u901a\u8fc7 .env \u6587\u4ef6\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf \u00b6 \u9664\u4e86\u8fd9\u79cd\u65b9\u5f0f\uff0cHttpRunner \u8fd8\u501f\u9274\u4e86 pipenv \u52a0\u8f7d .env \u7684\u65b9\u5f0f \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e2d\uff0c\u521b\u5efa .env \u6587\u4ef6\uff0c\u5e76\u5c06\u654f\u611f\u6570\u636e\u4fe1\u606f\u653e\u7f6e\u5230\u5176\u4e2d\uff0c\u5b58\u50a8\u91c7\u7528 name=value \u7684\u683c\u5f0f\uff1a $ cat .env UserName = admin Password = 123456 PROJECT_KEY = ABCDEFGH \u540c\u65f6\uff0c .env \u6587\u4ef6\u4e0d\u5e94\u8be5\u6dfb\u52a0\u5230\u4ee3\u7801\u4ed3\u5e93\u4e2d\uff0c\u5efa\u8bae\u5c06 .env \u52a0\u5165\u5230 .gitignore \u4e2d\u3002 HttpRunner \u8fd0\u884c\u65f6\uff0c\u4f1a\u81ea\u52a8\u5c06 .env \u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u52a0\u8f7d\u5230\u8fd0\u884c\u65f6\uff08RunTime\uff09\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u7136\u540e\u5728\u8fd0\u884c\u65f6\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u4e86\u3002 \u82e5\u9700\u52a0\u8f7d\u4e0d\u4f4d\u4e8e\u81ea\u52a8\u5316\u9879\u76ee\u6839\u76ee\u5f55\u4e2d\u7684 .env \uff0c\u6216\u8005\u5176\u5b83\u540d\u79f0\u7684 .env \u6587\u4ef6\uff08\u4f8b\u5982 production.env \uff09\uff0c\u53ef\u4ee5\u91c7\u7528 --dot-env-path \u53c2\u6570\u6307\u5b9a\u6587\u4ef6\u8def\u5f84\uff1a $ hrun /path/to/testcase.yml --dot-env-path /path/to/.env --log-level debug INFO Loading environment variables from /path/to/.env DEBUG Loaded variable: UserName DEBUG Loaded variable: Password DEBUG Loaded variable: PROJECT_KEY ... \u5f15\u7528\u73af\u5883\u53d8\u91cf \u00b6 \u5728 HttpRunner \u4e2d\u5185\u7f6e\u4e86\u51fd\u6570 environ \uff08\u7b80\u79f0 ENV \uff09\uff0c\u53ef\u7528\u4e8e\u5728 YAML/JSON \u811a\u672c\u4e2d\u76f4\u63a5\u5f15\u7528\u73af\u5883\u53d8\u91cf\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${ENV(Password)} validate : - eq : [ status_code , 200 ] \u82e5\u8fd8\u9700\u5bf9\u8bfb\u53d6\u7684\u73af\u5883\u53d8\u91cf\u505a\u8fdb\u4e00\u6b65\u5904\u7406\uff0c\u5219\u53ef\u4ee5\u5728 debugtalk.py \u901a\u8fc7 Python \u5185\u7f6e\u7684\u51fd\u6570 os.environ \u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e\u518d\u5b9e\u73b0\u5904\u7406\u903b\u8f91\u3002 \u4f8b\u5982\uff0c\u82e5\u53d1\u8d77\u8bf7\u6c42\u7684\u5bc6\u7801\u9700\u8981\u5148\u4e0e\u5bc6\u94a5\u8fdb\u884c\u62fc\u63a5\u5e76\u751f\u6210 MD5\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u6587\u4ef6\u4e2d\u5b9e\u73b0\u5982\u4e0b\u51fd\u6570\uff1a import os def get_encrypt_password (): raw_passwd = os . environ [ \"Password\" ] PROJECT_KEY = os . environ [ \"PROJECT_KEY\" ]) password = ( raw_passwd + PROJECT_KEY ) . encode ( 'ascii' ) return hmac . new ( password , hashlib . sha1 ) . hexdigest () \u7136\u540e\uff0c\u5728 YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7 ${func()} \u7684\u65b9\u5f0f\u5f15\u7528\u73af\u5883\u53d8\u91cf\u7684\u503c\u4e86\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${get_encrypt_password()} validate : - eq : [ status_code , 200 ]","title":"\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#_1","text":"\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u6709\u65f6\u9700\u8981\u501f\u52a9\u73af\u5883\u53d8\u91cf\u5b9e\u73b0\u67d0\u4e9b\u7279\u5b9a\u7684\u76ee\u7684\uff0c\u5e38\u89c1\u7684\u573a\u666f\u5305\u62ec\uff1a \u5207\u6362\u6d4b\u8bd5\u73af\u5883 \u5207\u6362\u6d4b\u8bd5\u914d\u7f6e \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u4ece \u4fe1\u606f\u5b89\u5168 \u7684\u89d2\u5ea6\u51fa\u53d1\uff09","title":"\u73af\u5883\u53d8\u91cf\u7684\u4f5c\u7528"},{"location":"prepare/dot-env/#_2","text":"","title":"\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#_3","text":"\u4f7f\u7528\u73af\u5883\u53d8\u91cf\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5728\u7cfb\u7edf\u4e2d\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u540d\u79f0\u548c\u503c\uff0c\u4f20\u7edf\u7684\u65b9\u5f0f\u4e3a\u4f7f\u7528 export \u547d\u4ee4\uff08Windows\u7cfb\u7edf\u4e2d\u4f7f\u7528 set \u547d\u4ee4\uff09\uff1a $ export UserName = admin $ echo $UserName admin $ export Password = 123456 $ echo $Password 123456 \u7136\u540e\uff0c\u5728\u7a0b\u5e8f\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u7cfb\u7edf\u4e2d\u7684\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u3002 $ python >>> import os >>> os.environ [ \"UserName\" ] 'admin'","title":"\u5728\u7ec8\u7aef\u4e2d\u9884\u8bbe\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#env","text":"\u9664\u4e86\u8fd9\u79cd\u65b9\u5f0f\uff0cHttpRunner \u8fd8\u501f\u9274\u4e86 pipenv \u52a0\u8f7d .env \u7684\u65b9\u5f0f \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e2d\uff0c\u521b\u5efa .env \u6587\u4ef6\uff0c\u5e76\u5c06\u654f\u611f\u6570\u636e\u4fe1\u606f\u653e\u7f6e\u5230\u5176\u4e2d\uff0c\u5b58\u50a8\u91c7\u7528 name=value \u7684\u683c\u5f0f\uff1a $ cat .env UserName = admin Password = 123456 PROJECT_KEY = ABCDEFGH \u540c\u65f6\uff0c .env \u6587\u4ef6\u4e0d\u5e94\u8be5\u6dfb\u52a0\u5230\u4ee3\u7801\u4ed3\u5e93\u4e2d\uff0c\u5efa\u8bae\u5c06 .env \u52a0\u5165\u5230 .gitignore \u4e2d\u3002 HttpRunner \u8fd0\u884c\u65f6\uff0c\u4f1a\u81ea\u52a8\u5c06 .env \u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u52a0\u8f7d\u5230\u8fd0\u884c\u65f6\uff08RunTime\uff09\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u7136\u540e\u5728\u8fd0\u884c\u65f6\u4e2d\u5c31\u53ef\u4ee5\u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u8bfb\u53d6\u4e86\u3002 \u82e5\u9700\u52a0\u8f7d\u4e0d\u4f4d\u4e8e\u81ea\u52a8\u5316\u9879\u76ee\u6839\u76ee\u5f55\u4e2d\u7684 .env \uff0c\u6216\u8005\u5176\u5b83\u540d\u79f0\u7684 .env \u6587\u4ef6\uff08\u4f8b\u5982 production.env \uff09\uff0c\u53ef\u4ee5\u91c7\u7528 --dot-env-path \u53c2\u6570\u6307\u5b9a\u6587\u4ef6\u8def\u5f84\uff1a $ hrun /path/to/testcase.yml --dot-env-path /path/to/.env --log-level debug INFO Loading environment variables from /path/to/.env DEBUG Loaded variable: UserName DEBUG Loaded variable: Password DEBUG Loaded variable: PROJECT_KEY ...","title":"\u901a\u8fc7 .env \u6587\u4ef6\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf"},{"location":"prepare/dot-env/#_4","text":"\u5728 HttpRunner \u4e2d\u5185\u7f6e\u4e86\u51fd\u6570 environ \uff08\u7b80\u79f0 ENV \uff09\uff0c\u53ef\u7528\u4e8e\u5728 YAML/JSON \u811a\u672c\u4e2d\u76f4\u63a5\u5f15\u7528\u73af\u5883\u53d8\u91cf\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${ENV(Password)} validate : - eq : [ status_code , 200 ] \u82e5\u8fd8\u9700\u5bf9\u8bfb\u53d6\u7684\u73af\u5883\u53d8\u91cf\u505a\u8fdb\u4e00\u6b65\u5904\u7406\uff0c\u5219\u53ef\u4ee5\u5728 debugtalk.py \u901a\u8fc7 Python \u5185\u7f6e\u7684\u51fd\u6570 os.environ \u5bf9\u73af\u5883\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e\u518d\u5b9e\u73b0\u5904\u7406\u903b\u8f91\u3002 \u4f8b\u5982\uff0c\u82e5\u53d1\u8d77\u8bf7\u6c42\u7684\u5bc6\u7801\u9700\u8981\u5148\u4e0e\u5bc6\u94a5\u8fdb\u884c\u62fc\u63a5\u5e76\u751f\u6210 MD5\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u6587\u4ef6\u4e2d\u5b9e\u73b0\u5982\u4e0b\u51fd\u6570\uff1a import os def get_encrypt_password (): raw_passwd = os . environ [ \"Password\" ] PROJECT_KEY = os . environ [ \"PROJECT_KEY\" ]) password = ( raw_passwd + PROJECT_KEY ) . encode ( 'ascii' ) return hmac . new ( password , hashlib . sha1 ) . hexdigest () \u7136\u540e\uff0c\u5728 YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7 ${func()} \u7684\u65b9\u5f0f\u5f15\u7528\u73af\u5883\u53d8\u91cf\u7684\u503c\u4e86\u3002 - test : name : login request : url : http://host/api/login method : POST headers : Content-Type : application/json json : username : ${ENV(UserName)} password : ${get_encrypt_password()} validate : - eq : [ status_code , 200 ]","title":"\u5f15\u7528\u73af\u5883\u53d8\u91cf"},{"location":"prepare/parameters/","text":"\u4ecb\u7ecd \u00b6 \u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u7ecf\u5e38\u4f1a\u9047\u5230\u5982\u4e0b\u573a\u666f\uff1a \u6d4b\u8bd5\u641c\u7d22\u529f\u80fd\uff0c\u53ea\u6709\u4e00\u4e2a\u641c\u7d22\u8f93\u5165\u6846\uff0c\u4f46\u6709 10 \u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u641c\u7d22\u5173\u952e\u5b57\uff1b \u6d4b\u8bd5\u8d26\u53f7\u767b\u5f55\u529f\u80fd\uff0c\u9700\u8981\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u6309\u7167\u7b49\u4ef7\u7c7b\u5212\u5206\u540e\u6709 20 \u79cd\u7ec4\u5408\u60c5\u51b5\u3002 \u8fd9\u91cc\u53ea\u662f\u968f\u610f\u627e\u4e86\u4e24\u4e2a\u5178\u578b\u7684\u4f8b\u5b50\uff0c\u76f8\u4fe1\u5927\u5bb6\u90fd\u6709\u9047\u5230\u8fc7\u5f88\u591a\u7c7b\u4f3c\u7684\u573a\u666f\u3002\u603b\u7ed3\u4e0b\u6765\uff0c\u5c31\u662f\u5728\u6211\u4eec\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u811a\u672c\u4e2d\u5b58\u5728\u53c2\u6570\uff0c\u5e76\u4e14\u6211\u4eec\u9700\u8981\u91c7\u7528\u4e0d\u540c\u7684\u53c2\u6570\u53bb\u8fd0\u884c\u3002 \u7ecf\u8fc7\u6982\u62ec\uff0c\u53c2\u6570\u57fa\u672c\u4e0a\u5206\u4e3a\u4e24\u79cd\u7c7b\u578b\uff1a \u5355\u4e2a\u72ec\u7acb\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e00\u79cd\u573a\u666f\uff0c\u6211\u4eec\u53ea\u9700\u8981\u53d8\u6362\u641c\u7d22\u5173\u952e\u5b57\u8fd9\u4e00\u4e2a\u53c2\u6570 \u591a\u4e2a\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e8c\u79cd\u573a\u666f\uff0c\u6211\u4eec\u9700\u8981\u53d8\u6362\u7528\u6237\u540d\u548c\u5bc6\u7801\u4e24\u4e2a\u53c2\u6570\uff0c\u5e76\u4e14\u8fd9\u4e24\u4e2a\u53c2\u6570\u9700\u8981\u5173\u8054\u7ec4\u5408 \u7136\u540e\uff0c\u5bf9\u4e8e\u53c2\u6570\u800c\u8a00\uff0c\u6211\u4eec\u53ef\u80fd\u5177\u6709\u4e00\u4e2a\u53c2\u6570\u5217\u8868\uff0c\u5728\u811a\u672c\u8fd0\u884c\u65f6\u9700\u8981\u6309\u7167\u4e0d\u540c\u7684\u89c4\u5219\u53bb\u53d6\u503c\uff0c\u4f8b\u5982\u987a\u5e8f\u53d6\u503c\u3001\u968f\u673a\u53d6\u503c\u3001\u5faa\u73af\u53d6\u503c\u7b49\u7b49\u3002 \u8fd9\u5c31\u662f\u5178\u578b\u7684\u53c2\u6570\u5316\u548c\u6570\u636e\u9a71\u52a8\u3002 \u5982\u9700\u4e86\u89e3 HttpRunner \u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u7684\u5b9e\u73b0\u539f\u7406\u548c\u6280\u672f\u7ec6\u8282\uff0c\u53ef\u524d\u5f80\u9605\u8bfb \u300aHttpRunner \u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u300b \u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u51c6\u5907 \u00b6 \u4ece 2.0.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u4e0d\u518d\u652f\u6301\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\uff1b\u53c2\u6570\u5316\u7684\u529f\u80fd\u9700\u8981\u5728 testsuite \u4e2d\u5b9e\u73b0\u3002\u53d8\u66f4\u7684\u76ee\u7684\u662f\u8ba9\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6982\u5ff5\u66f4\u7eaf\u7cb9\uff0c\u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u548c\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u6982\u5ff5\u5b9a\u4e49\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002 \u53c2\u6570\u5316\u673a\u5236\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u4e2d\u5b9e\u73b0\u3002\u5982\u9700\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a testsuite\uff0c\u5728 testsuite \u4e2d\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u5b9a\u4e49\u53c2\u6570\u5316\u914d\u7f6e\u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u7684\u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a config : name : testsuite description testcases : testcase1_name : testcase : /path/to/testcase1 testcase2_name : testcase : /path/to/testcase2 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0ctestsuite \u548c testcase \u7684\u683c\u5f0f\u5b58\u5728\u8f83\u5927\u533a\u522b\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002 \u53c2\u6570\u914d\u7f6e\u6982\u8ff0 \u00b6 \u5982\u9700\u5bf9\u67d0\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u9700\u8981\u4f7f\u7528 parameters \u5173\u952e\u5b57\uff0c\u5b9a\u4e49\u53c2\u6570\u540d\u79f0\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u53c2\u6570\u540d\u79f0\u7684\u5b9a\u4e49\u5206\u4e3a\u4e24\u79cd\u60c5\u51b5\uff1a \u72ec\u7acb\u53c2\u6570\u5355\u72ec\u8fdb\u884c\u5b9a\u4e49\uff1b \u591a\u4e2a\u53c2\u6570\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\u9700\u8981\u5c06\u5176\u5b9a\u4e49\u5728\u4e00\u8d77\uff0c\u91c7\u7528\u77ed\u6a2a\u7ebf\uff08 - \uff09\u8fdb\u884c\u8fde\u63a5\u3002 \u6570\u636e\u6e90\u6307\u5b9a\u652f\u6301\u4e09\u79cd\u65b9\u5f0f\uff1a \u5728 YAML/JSON \u4e2d\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7b80\u5355\u6613\u7528\uff0c\u9002\u5408\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5 \u901a\u8fc7\u5185\u7f6e\u7684 parameterize\uff08\u53ef\u7b80\u5199\u4e3aP\uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\uff1a\u8be5\u79cd\u65b9\u5f0f\u9700\u8981\u51c6\u5907 CSV \u6570\u636e\u6587\u4ef6\uff0c\u9002\u5408\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5 \u8c03\u7528 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7075\u6d3b\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49 Python \u51fd\u6570\u5b9e\u73b0\u4efb\u610f\u573a\u666f\u7684\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u5f53\u9700\u8981\u52a8\u6001\u751f\u6210\u53c2\u6570\u5217\u8868\u65f6\u4e5f\u9700\u8981\u9009\u62e9\u8be5\u79cd\u65b9\u5f0f \u4e09\u79cd\u65b9\u5f0f\u53ef\u6839\u636e\u5b9e\u9645\u9879\u76ee\u9700\u6c42\u8fdb\u884c\u7075\u6d3b\u9009\u62e9\uff0c\u540c\u65f6\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u7684\u7ec4\u5408\u4f7f\u7528\u3002\u5047\u5982\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u4e86\u591a\u4e2a\u53c2\u6570\uff0c\u90a3\u4e48\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u4f1a\u5bf9\u53c2\u6570\u8fdb\u884c\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u8986\u76d6\u6240\u6709\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u4f7f\u7528\u65b9\u5f0f\u6982\u89c8\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] user_id : ${P(user_id.csv)} username-password : ${get_account(10)} \u53c2\u6570\u914d\u7f6e\u8be6\u89e3 \u00b6 \u5c06\u53c2\u6570\u540d\u79f0\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u6307\u5b9a\u65b9\u5f0f\u8fdb\u884c\u7ec4\u5408\uff0c\u5171\u6709 6 \u79cd\u5f62\u5f0f\u3002\u73b0\u5206\u522b\u9488\u5bf9\u6bcf\u4e00\u7c7b\u60c5\u51b5\u8fdb\u884c\u8be6\u7ec6\u8bf4\u660e\u3002 \u72ec\u7acb\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868 \u00b6 \u5bf9\u4e8e\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5\uff0c\u6700\u7b80\u5355\u7684\u65b9\u5f0f\u662f\u76f4\u63a5\u5728 YAML/JSON \u4e2d\u6307\u5b9a\u53c2\u6570\u5217\u8868\u5185\u5bb9\u3002 \u4f8b\u5982\uff0c\u5bf9\u4e8e\u72ec\u7acb\u53c2\u6570 user_id \uff0c\u53c2\u6570\u5217\u8868\u4e3a [1001, 1002, 1003, 1004] \uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 user_id \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 [1001, 1002, 1003, 1004] \u56db\u4e2a\u503c\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u3002 \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002 \u5173\u8054\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868 \u00b6 \u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : - [ \"user1\" , \"111111\" ] - [ \"user2\" , \"222222\" ] - [ \"user3\" , \"333333\" ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 username \u548c password \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 {\"username\": \"user1\", \"password\": \"111111\"} \u3001 {\"username\": \"user2\", \"password\": \"222222\"} \u3001 {\"username\": \"user3\", \"password\": \"333333\"} \u8fd0\u884c 3 \u6b21\u6d4b\u8bd5\uff0c\u5e76\u4e14\u4fdd\u8bc1\u53c2\u6570\u503c\u603b\u662f\u6210\u5bf9\u4f7f\u7528\u3002 \u72ec\u7acb\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6 \u00b6 \u5bf9\u4e8e\u5df2\u6709\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4e14\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5\uff0c\u6bd4\u8f83\u9002\u5408\u7684\u65b9\u5f0f\u662f\u5c06\u53c2\u6570\u5217\u8868\u503c\u5b58\u50a8\u5728 CSV \u6570\u636e\u6587\u4ef6\u4e2d\u3002 \u5bf9\u4e8e CSV \u6570\u636e\u6587\u4ef6\uff0c\u9700\u8981\u9075\u5faa\u5982\u4e0b\u51e0\u9879\u7ea6\u5b9a\u7684\u89c4\u5219\uff1a CSV \u6587\u4ef6\u4e2d\u7684\u7b2c\u4e00\u884c\u5fc5\u987b\u4e3a\u53c2\u6570\u540d\u79f0\uff0c\u4ece\u7b2c\u4e8c\u884c\u5f00\u59cb\u4e3a\u53c2\u6570\u503c\uff0c\u6bcf\u4e2a\uff08\u7ec4\uff09\u503c\u5360\u4e00\u884c\uff1b \u82e5\u540c\u4e00\u4e2a CSV \u6587\u4ef6\u4e2d\u5177\u6709\u591a\u4e2a\u53c2\u6570\uff0c\u5219\u53c2\u6570\u540d\u79f0\u548c\u6570\u503c\u7684\u95f4\u9694\u7b26\u9700\u5b9e\u7528\u82f1\u6587\u9017\u53f7\uff1b \u5728 YAML/JSON \u6587\u4ef6\u5f15\u7528 CSV \u6587\u4ef6\u65f6\uff0c\u6587\u4ef6\u8def\u5f84\u4e3a\u57fa\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\uff08debugtalk.py \u6240\u5728\u8def\u5f84\uff09\u7684\u76f8\u5bf9\u8def\u5f84\u3002 \u4f8b\u5982\uff0cuser_id \u7684\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e2000\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u521b\u5efa user_id.csv\uff0c\u5e76\u4e14\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 user_id 1001 1002 ... 1999 2000 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0cuser_id.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 user_id.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${P(data/user_id.csv)} \u5373 P \u51fd\u6570\u7684\u53c2\u6570\uff08CSV \u6587\u4ef6\u8def\u5f84\uff09\u662f\u76f8\u5bf9\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684\u76f8\u5bf9\u8def\u5f84\u3002\u5f53\u7136\uff0c\u8fd9\u91cc\u4e5f\u53ef\u4ee5\u4f7f\u7528 CSV \u6587\u4ef6\u5728\u7cfb\u7edf\u4e2d\u7684\u7edd\u5bf9\u8def\u5f84\uff0c\u4e0d\u8fc7\u8fd9\u6837\u7684\u8bdd\u5728\u9879\u76ee\u8def\u5f84\u53d8\u52a8\u65f6\u5c31\u4f1a\u51fa\u73b0\u95ee\u9898\uff0c\u56e0\u6b64\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\u7684\u5f62\u5f0f\u3002 \u5173\u8054\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6 \u00b6 \u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa account.csv \uff0c\u5e76\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 username,password test1,111111 test2,222222 test3,333333 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0caccount.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 account.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${P(data/account.csv)} \u9700\u8981\u8bf4\u660e\u7684\u662f\uff0c\u5728 parameters \u4e2d\u6307\u5b9a\u7684\u53c2\u6570\u540d\u79f0\u5fc5\u987b\u4e0e CSV \u6587\u4ef6\u4e2d\u7b2c\u4e00\u884c\u7684\u53c2\u6570\u540d\u79f0\u4e00\u81f4\uff0c\u987a\u5e8f\u53ef\u4ee5\u4e0d\u4e00\u81f4\uff0c\u53c2\u6570\u4e2a\u6570\u4e5f\u53ef\u4ee5\u4e0d\u4e00\u81f4\u3002 \u4f8b\u5982\uff0c\u5728 account.csv \u6587\u4ef6\u4e2d\u53ef\u4ee5\u5305\u542b\u591a\u4e2a\u53c2\u6570\uff0cusername\u3001password\u3001phone\u3001age\uff1a username,password,phone,age test1,111111,18600000001,21 test2,222222,18600000002,22 test3,333333,18600000003,23 \u800c\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u6307\u5b9a\u53c2\u6570\u65f6\uff0c\u53ef\u4ee5\u53ea\u4f7f\u7528\u90e8\u5206\u53c2\u6570\uff0c\u5e76\u4e14\u53c2\u6570\u987a\u5e8f\u65e0\u9700\u4e0e CSV \u6587\u4ef6\u4e2d\u53c2\u6570\u540d\u79f0\u7684\u987a\u5e8f\u4e00\u81f4\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : phone-username : ${P(account.csv)} \u72ec\u7acb\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 \u00b6 \u5bf9\u4e8e\u6ca1\u6709\u73b0\u6210\u53c2\u6570\u5217\u8868\uff0c\u6216\u8005\u9700\u8981\u66f4\u7075\u6d3b\u7684\u65b9\u5f0f\u52a8\u6001\u751f\u6210\u53c2\u6570\u7684\u60c5\u51b5\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5e76\u5728 YAML/JSON \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u82e5\u9700\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e1004\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u8fd4\u56de\u53c2\u6570\u5217\u8868\u3002 def get_user_id (): return [ { \"user_id\" : 1001 }, { \"user_id\" : 1002 }, { \"user_id\" : 1003 }, { \"user_id\" : 1004 } ] \u7136\u540e\uff0c\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u6765\u6307\u5b9a\u6570\u636e\u6e90\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${get_user_id()} \u53e6\u5916\uff0c\u901a\u8fc7\u51fd\u6570\u7684\u4f20\u53c2\u673a\u5236\uff0c\u8fd8\u53ef\u4ee5\u5b9e\u73b0\u66f4\u7075\u6d3b\u7684\u53c2\u6570\u751f\u6210\u529f\u80fd\uff0c\u5728\u8c03\u7528\u51fd\u6570\u65f6\u6307\u5b9a\u9700\u8981\u751f\u6210\u7684\u53c2\u6570\u4e2a\u6570\u3002 \u5173\u8054\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 \u00b6 \u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u5b9e\u73b0\u65b9\u5f0f\u4e5f\u7c7b\u4f3c\u3002 \u4f8b\u5982\uff0c\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u51fd\u6570 get_account\uff0c\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u8d26\u53f7\u5bc6\u7801\u53c2\u6570\u5217\u8868\u3002 def get_account ( num ): accounts = [] for index in range ( 1 , num + 1 ): accounts . append ( { \"username\" : \"user %s \" % index , \"password\" : str ( index ) * 6 }, ) return accounts \u90a3\u4e48\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u53c2\u6570\u5217\u8868\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${get_account(10)} \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728\u81ea\u5b9a\u4e49\u51fd\u6570\u4e2d\uff0c\u751f\u6210\u7684\u53c2\u6570\u5217\u8868\u5fc5\u987b\u4e3a list of dict \u7684\u6570\u636e\u7ed3\u6784\uff0c\u8be5\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u4e0e CSV \u6587\u4ef6\u7684\u5904\u7406\u673a\u5236\u4fdd\u6301\u4e00\u81f4\u3002 \u53c2\u6570\u5316\u8fd0\u884c \u00b6 \u5b8c\u6210\u4ee5\u4e0a\u53c2\u6570\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u51c6\u5907\u5de5\u4f5c\u4e4b\u540e\uff0c\u53c2\u6570\u5316\u8fd0\u884c\u4e0e\u666e\u901a\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u5b8c\u5168\u4e00\u81f4\u3002 \u91c7\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff1a $ hrun tests/data/demo_parameters.yml \u91c7\u7528 locusts \u547d\u4ee4\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5\uff1a $ locusts -f tests/data/demo_parameters.yml \u533a\u522b\u5728\u4e8e\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u65f6\u904d\u5386\u4e00\u904d\u540e\u4f1a\u7ec8\u6b62\u6267\u884c\uff0c\u6027\u80fd\u6d4b\u8bd5\u65f6\u6bcf\u4e2a\u5e76\u53d1\u7528\u6237\u90fd\u4f1a\u5faa\u73af\u904d\u5386\u6240\u6709\u53c2\u6570\u3002 \u6848\u4f8b\u6f14\u793a \u00b6 \u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u83b7\u53d6 token \u7684 \u6d4b\u8bd5\u7528\u4f8b \u3002 \u70b9\u51fb\u67e5\u770b YAML \u6d4b\u8bd5\u7528\u4f8b - config : name : get token base_url : http://127.0.0.1:5000 variables : device_sn : ${gen_random_string(15)} os_platform : 'ios' app_version : '2.8.6' - test : name : get token with $device_sn, $os_platform, $app_version request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : $app_version device_sn : $device_sn os_platform : $os_platform json : sign : ${get_sign($device_sn, $os_platform, $app_version)} method : POST url : /api/get-token extract : token : content.token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528 device_sn\u3001app_version \u548c os_platform \u8fd9\u4e09\u4e2a\u53c2\u6570\u6765\u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a testsuite \uff0c\u5e76\u4e14\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\u3002 config : name : get token with parameters testcases : get token with $user_agent, $app_version, $os_platform : testcase : demo-testcase-get-token.yml parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] app_version : ${P(app_version.csv)} os_platform : ${get_os_platform()} \u5176\u4e2d\uff0c user_agent \u4f7f\u7528\u4e86\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u7684\u5f62\u5f0f\u3002 app_version \u901a\u8fc7 CSV \u6587\u4ef6\u8fdb\u884c\u53c2\u6570\u914d\u7f6e\uff0c\u5bf9\u5e94\u7684\u6587\u4ef6\u5185\u5bb9\u4e3a\uff1a app_version 2.8.5 2.8.6 os_platform \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5bf9\u5e94\u7684\u51fd\u6570\u5185\u5bb9\u4e3a\uff1a def get_os_platform (): return [ { \"os_platform\" : \"ios\" }, { \"os_platform\" : \"android\" } ] \u90a3\u4e48\uff0c\u7ecf\u8fc7\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u5e94\u8be5\u603b\u5171\u6709 3*2*2=12 \u79cd\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u70b9\u51fb\u67e5\u770b\u5b8c\u6574\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-parameters-get-token.yml INFO Start to run testcase: get token with iOS/10.1, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.66 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.026s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.76 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.012s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.49 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.39 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.04 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.44 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.14 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 7.62 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.010s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.88 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.41 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1551950193.html","title":"\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8"},{"location":"prepare/parameters/#_1","text":"\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u4e2d\uff0c\u7ecf\u5e38\u4f1a\u9047\u5230\u5982\u4e0b\u573a\u666f\uff1a \u6d4b\u8bd5\u641c\u7d22\u529f\u80fd\uff0c\u53ea\u6709\u4e00\u4e2a\u641c\u7d22\u8f93\u5165\u6846\uff0c\u4f46\u6709 10 \u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u641c\u7d22\u5173\u952e\u5b57\uff1b \u6d4b\u8bd5\u8d26\u53f7\u767b\u5f55\u529f\u80fd\uff0c\u9700\u8981\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u6309\u7167\u7b49\u4ef7\u7c7b\u5212\u5206\u540e\u6709 20 \u79cd\u7ec4\u5408\u60c5\u51b5\u3002 \u8fd9\u91cc\u53ea\u662f\u968f\u610f\u627e\u4e86\u4e24\u4e2a\u5178\u578b\u7684\u4f8b\u5b50\uff0c\u76f8\u4fe1\u5927\u5bb6\u90fd\u6709\u9047\u5230\u8fc7\u5f88\u591a\u7c7b\u4f3c\u7684\u573a\u666f\u3002\u603b\u7ed3\u4e0b\u6765\uff0c\u5c31\u662f\u5728\u6211\u4eec\u7684\u81ea\u52a8\u5316\u6d4b\u8bd5\u811a\u672c\u4e2d\u5b58\u5728\u53c2\u6570\uff0c\u5e76\u4e14\u6211\u4eec\u9700\u8981\u91c7\u7528\u4e0d\u540c\u7684\u53c2\u6570\u53bb\u8fd0\u884c\u3002 \u7ecf\u8fc7\u6982\u62ec\uff0c\u53c2\u6570\u57fa\u672c\u4e0a\u5206\u4e3a\u4e24\u79cd\u7c7b\u578b\uff1a \u5355\u4e2a\u72ec\u7acb\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e00\u79cd\u573a\u666f\uff0c\u6211\u4eec\u53ea\u9700\u8981\u53d8\u6362\u641c\u7d22\u5173\u952e\u5b57\u8fd9\u4e00\u4e2a\u53c2\u6570 \u591a\u4e2a\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\uff1a\u4f8b\u5982\u524d\u9762\u7684\u7b2c\u4e8c\u79cd\u573a\u666f\uff0c\u6211\u4eec\u9700\u8981\u53d8\u6362\u7528\u6237\u540d\u548c\u5bc6\u7801\u4e24\u4e2a\u53c2\u6570\uff0c\u5e76\u4e14\u8fd9\u4e24\u4e2a\u53c2\u6570\u9700\u8981\u5173\u8054\u7ec4\u5408 \u7136\u540e\uff0c\u5bf9\u4e8e\u53c2\u6570\u800c\u8a00\uff0c\u6211\u4eec\u53ef\u80fd\u5177\u6709\u4e00\u4e2a\u53c2\u6570\u5217\u8868\uff0c\u5728\u811a\u672c\u8fd0\u884c\u65f6\u9700\u8981\u6309\u7167\u4e0d\u540c\u7684\u89c4\u5219\u53bb\u53d6\u503c\uff0c\u4f8b\u5982\u987a\u5e8f\u53d6\u503c\u3001\u968f\u673a\u53d6\u503c\u3001\u5faa\u73af\u53d6\u503c\u7b49\u7b49\u3002 \u8fd9\u5c31\u662f\u5178\u578b\u7684\u53c2\u6570\u5316\u548c\u6570\u636e\u9a71\u52a8\u3002 \u5982\u9700\u4e86\u89e3 HttpRunner \u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u7684\u5b9e\u73b0\u539f\u7406\u548c\u6280\u672f\u7ec6\u8282\uff0c\u53ef\u524d\u5f80\u9605\u8bfb \u300aHttpRunner \u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\u673a\u5236\u300b \u3002","title":"\u4ecb\u7ecd"},{"location":"prepare/parameters/#testsuite","text":"\u4ece 2.0.0 \u7248\u672c\u5f00\u59cb\uff0cHttpRunner \u4e0d\u518d\u652f\u6301\u5728\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\uff1b\u53c2\u6570\u5316\u7684\u529f\u80fd\u9700\u8981\u5728 testsuite \u4e2d\u5b9e\u73b0\u3002\u53d8\u66f4\u7684\u76ee\u7684\u662f\u8ba9\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u7684\u6982\u5ff5\u66f4\u7eaf\u7cb9\uff0c\u5173\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u548c\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u6982\u5ff5\u5b9a\u4e49\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002 \u53c2\u6570\u5316\u673a\u5236\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u4e2d\u5b9e\u73b0\u3002\u5982\u9700\u5b9e\u73b0\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2a testsuite\uff0c\u5728 testsuite \u4e2d\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u5b9a\u4e49\u53c2\u6570\u5316\u914d\u7f6e\u3002 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u7684\u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a config : name : testsuite description testcases : testcase1_name : testcase : /path/to/testcase1 testcase2_name : testcase : /path/to/testcase2 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0ctestsuite \u548c testcase \u7684\u683c\u5f0f\u5b58\u5728\u8f83\u5927\u533a\u522b\uff0c\u8be6\u89c1 \u300a\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u300b \u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u51c6\u5907"},{"location":"prepare/parameters/#_2","text":"\u5982\u9700\u5bf9\u67d0\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5b9e\u73b0\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u9700\u8981\u4f7f\u7528 parameters \u5173\u952e\u5b57\uff0c\u5b9a\u4e49\u53c2\u6570\u540d\u79f0\u5e76\u6307\u5b9a\u6570\u636e\u6e90\u53d6\u503c\u65b9\u5f0f\u3002 \u53c2\u6570\u540d\u79f0\u7684\u5b9a\u4e49\u5206\u4e3a\u4e24\u79cd\u60c5\u51b5\uff1a \u72ec\u7acb\u53c2\u6570\u5355\u72ec\u8fdb\u884c\u5b9a\u4e49\uff1b \u591a\u4e2a\u53c2\u6570\u5177\u6709\u5173\u8054\u6027\u7684\u53c2\u6570\u9700\u8981\u5c06\u5176\u5b9a\u4e49\u5728\u4e00\u8d77\uff0c\u91c7\u7528\u77ed\u6a2a\u7ebf\uff08 - \uff09\u8fdb\u884c\u8fde\u63a5\u3002 \u6570\u636e\u6e90\u6307\u5b9a\u652f\u6301\u4e09\u79cd\u65b9\u5f0f\uff1a \u5728 YAML/JSON \u4e2d\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7b80\u5355\u6613\u7528\uff0c\u9002\u5408\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5 \u901a\u8fc7\u5185\u7f6e\u7684 parameterize\uff08\u53ef\u7b80\u5199\u4e3aP\uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\uff1a\u8be5\u79cd\u65b9\u5f0f\u9700\u8981\u51c6\u5907 CSV \u6570\u636e\u6587\u4ef6\uff0c\u9002\u5408\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5 \u8c03\u7528 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff1a\u8be5\u79cd\u65b9\u5f0f\u6700\u4e3a\u7075\u6d3b\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49 Python \u51fd\u6570\u5b9e\u73b0\u4efb\u610f\u573a\u666f\u7684\u6570\u636e\u9a71\u52a8\u673a\u5236\uff0c\u5f53\u9700\u8981\u52a8\u6001\u751f\u6210\u53c2\u6570\u5217\u8868\u65f6\u4e5f\u9700\u8981\u9009\u62e9\u8be5\u79cd\u65b9\u5f0f \u4e09\u79cd\u65b9\u5f0f\u53ef\u6839\u636e\u5b9e\u9645\u9879\u76ee\u9700\u6c42\u8fdb\u884c\u7075\u6d3b\u9009\u62e9\uff0c\u540c\u65f6\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u7684\u7ec4\u5408\u4f7f\u7528\u3002\u5047\u5982\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u4e86\u591a\u4e2a\u53c2\u6570\uff0c\u90a3\u4e48\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u4f1a\u5bf9\u53c2\u6570\u8fdb\u884c\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u8986\u76d6\u6240\u6709\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u4f7f\u7528\u65b9\u5f0f\u6982\u89c8\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] user_id : ${P(user_id.csv)} username-password : ${get_account(10)}","title":"\u53c2\u6570\u914d\u7f6e\u6982\u8ff0"},{"location":"prepare/parameters/#_3","text":"\u5c06\u53c2\u6570\u540d\u79f0\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u6307\u5b9a\u65b9\u5f0f\u8fdb\u884c\u7ec4\u5408\uff0c\u5171\u6709 6 \u79cd\u5f62\u5f0f\u3002\u73b0\u5206\u522b\u9488\u5bf9\u6bcf\u4e00\u7c7b\u60c5\u51b5\u8fdb\u884c\u8be6\u7ec6\u8bf4\u660e\u3002","title":"\u53c2\u6570\u914d\u7f6e\u8be6\u89e3"},{"location":"prepare/parameters/#_4","text":"\u5bf9\u4e8e\u53c2\u6570\u5217\u8868\u6bd4\u8f83\u5c0f\u7684\u60c5\u51b5\uff0c\u6700\u7b80\u5355\u7684\u65b9\u5f0f\u662f\u76f4\u63a5\u5728 YAML/JSON \u4e2d\u6307\u5b9a\u53c2\u6570\u5217\u8868\u5185\u5bb9\u3002 \u4f8b\u5982\uff0c\u5bf9\u4e8e\u72ec\u7acb\u53c2\u6570 user_id \uff0c\u53c2\u6570\u5217\u8868\u4e3a [1001, 1002, 1003, 1004] \uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : testcase description testcases : create user : testcase : demo-quickstart-6.yml parameters : user_id : [ 1001 , 1002 , 1003 , 1004 ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 user_id \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 [1001, 1002, 1003, 1004] \u56db\u4e2a\u503c\u8fd0\u884c\u6d4b\u8bd5\u7528\u4f8b\u3002 \u70b9\u51fb\u67e5\u770b\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-quickstart-7.json INFO Start to run testcase: create user 1001 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 8.95 ms, response_length: 46 bytes . /api/users/1001 INFO POST http://127.0.0.1:5000/api/users/1001 INFO status_code: 201, response_time(ms): 3.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.021s OK INFO Start to run testcase: create user 1002 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.78 ms, response_length: 46 bytes . /api/users/1002 INFO POST http://127.0.0.1:5000/api/users/1002 INFO status_code: 201, response_time(ms): 2.84 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK INFO Start to run testcase: create user 1003 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 2.92 ms, response_length: 46 bytes . /api/users/1003 INFO POST http://127.0.0.1:5000/api/users/1003 INFO status_code: 201, response_time(ms): 5.56 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.011s OK INFO Start to run testcase: create user 1004 /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.25 ms, response_length: 46 bytes . /api/users/1004 INFO POST http://127.0.0.1:5000/api/users/1004 INFO status_code: 201, response_time(ms): 7.02 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.016s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548518757.html \u53ef\u4ee5\u770b\u51fa\uff0c\u6d4b\u8bd5\u7528\u4f8b\u603b\u5171\u8fd0\u884c\u4e86 4 \u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u8fd0\u884c\u65f6\u90fd\u662f\u91c7\u7528\u7684\u4e0d\u540c user_id\u3002","title":"\u72ec\u7acb\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868"},{"location":"prepare/parameters/#_5","text":"\u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u6309\u7167\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u914d\u7f6e\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : - [ \"user1\" , \"111111\" ] - [ \"user2\" , \"222222\" ] - [ \"user3\" , \"333333\" ] \u8fdb\u884c\u8be5\u914d\u7f6e\u540e\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u65f6\u5c31\u4f1a\u5bf9 username \u548c password \u5b9e\u73b0\u6570\u636e\u9a71\u52a8\uff0c\u5373\u5206\u522b\u4f7f\u7528 {\"username\": \"user1\", \"password\": \"111111\"} \u3001 {\"username\": \"user2\", \"password\": \"222222\"} \u3001 {\"username\": \"user3\", \"password\": \"333333\"} \u8fd0\u884c 3 \u6b21\u6d4b\u8bd5\uff0c\u5e76\u4e14\u4fdd\u8bc1\u53c2\u6570\u503c\u603b\u662f\u6210\u5bf9\u4f7f\u7528\u3002","title":"\u5173\u8054\u53c2\u6570 & \u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868"},{"location":"prepare/parameters/#csv","text":"\u5bf9\u4e8e\u5df2\u6709\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4e14\u6570\u636e\u91cf\u6bd4\u8f83\u5927\u7684\u60c5\u51b5\uff0c\u6bd4\u8f83\u9002\u5408\u7684\u65b9\u5f0f\u662f\u5c06\u53c2\u6570\u5217\u8868\u503c\u5b58\u50a8\u5728 CSV \u6570\u636e\u6587\u4ef6\u4e2d\u3002 \u5bf9\u4e8e CSV \u6570\u636e\u6587\u4ef6\uff0c\u9700\u8981\u9075\u5faa\u5982\u4e0b\u51e0\u9879\u7ea6\u5b9a\u7684\u89c4\u5219\uff1a CSV \u6587\u4ef6\u4e2d\u7684\u7b2c\u4e00\u884c\u5fc5\u987b\u4e3a\u53c2\u6570\u540d\u79f0\uff0c\u4ece\u7b2c\u4e8c\u884c\u5f00\u59cb\u4e3a\u53c2\u6570\u503c\uff0c\u6bcf\u4e2a\uff08\u7ec4\uff09\u503c\u5360\u4e00\u884c\uff1b \u82e5\u540c\u4e00\u4e2a CSV \u6587\u4ef6\u4e2d\u5177\u6709\u591a\u4e2a\u53c2\u6570\uff0c\u5219\u53c2\u6570\u540d\u79f0\u548c\u6570\u503c\u7684\u95f4\u9694\u7b26\u9700\u5b9e\u7528\u82f1\u6587\u9017\u53f7\uff1b \u5728 YAML/JSON \u6587\u4ef6\u5f15\u7528 CSV \u6587\u4ef6\u65f6\uff0c\u6587\u4ef6\u8def\u5f84\u4e3a\u57fa\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\uff08debugtalk.py \u6240\u5728\u8def\u5f84\uff09\u7684\u76f8\u5bf9\u8def\u5f84\u3002 \u4f8b\u5982\uff0cuser_id \u7684\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e2000\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u521b\u5efa user_id.csv\uff0c\u5e76\u4e14\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 user_id 1001 1002 ... 1999 2000 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0cuser_id.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 user_id.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${P(data/user_id.csv)} \u5373 P \u51fd\u6570\u7684\u53c2\u6570\uff08CSV \u6587\u4ef6\u8def\u5f84\uff09\u662f\u76f8\u5bf9\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684\u76f8\u5bf9\u8def\u5f84\u3002\u5f53\u7136\uff0c\u8fd9\u91cc\u4e5f\u53ef\u4ee5\u4f7f\u7528 CSV \u6587\u4ef6\u5728\u7cfb\u7edf\u4e2d\u7684\u7edd\u5bf9\u8def\u5f84\uff0c\u4e0d\u8fc7\u8fd9\u6837\u7684\u8bdd\u5728\u9879\u76ee\u8def\u5f84\u53d8\u52a8\u65f6\u5c31\u4f1a\u51fa\u73b0\u95ee\u9898\uff0c\u56e0\u6b64\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\u7684\u5f62\u5f0f\u3002","title":"\u72ec\u7acb\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6"},{"location":"prepare/parameters/#csv_1","text":"\u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u4f8b\u5982 username \u548c password\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa account.csv \uff0c\u5e76\u5728\u6587\u4ef6\u4e2d\u6309\u7167\u5982\u4e0b\u5f62\u5f0f\u8fdb\u884c\u63cf\u8ff0\u3002 username,password test1,111111 test2,222222 test3,333333 \u7136\u540e\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u901a\u8fc7\u5185\u7f6e\u7684 parameterize \uff08\u53ef\u7b80\u5199\u4e3a P \uff09\u51fd\u6570\u5f15\u7528 CSV \u6587\u4ef6\u3002 \u5047\u8bbe\u9879\u76ee\u7684\u6839\u76ee\u5f55\u4e0b\u6709 data \u6587\u4ef6\u5939\uff0caccount.csv \u4f4d\u4e8e\u5176\u4e2d\uff0c\u90a3\u4e48 account.csv \u7684\u5f15\u7528\u63cf\u8ff0\u5982\u4e0b\uff1a config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${P(data/account.csv)} \u9700\u8981\u8bf4\u660e\u7684\u662f\uff0c\u5728 parameters \u4e2d\u6307\u5b9a\u7684\u53c2\u6570\u540d\u79f0\u5fc5\u987b\u4e0e CSV \u6587\u4ef6\u4e2d\u7b2c\u4e00\u884c\u7684\u53c2\u6570\u540d\u79f0\u4e00\u81f4\uff0c\u987a\u5e8f\u53ef\u4ee5\u4e0d\u4e00\u81f4\uff0c\u53c2\u6570\u4e2a\u6570\u4e5f\u53ef\u4ee5\u4e0d\u4e00\u81f4\u3002 \u4f8b\u5982\uff0c\u5728 account.csv \u6587\u4ef6\u4e2d\u53ef\u4ee5\u5305\u542b\u591a\u4e2a\u53c2\u6570\uff0cusername\u3001password\u3001phone\u3001age\uff1a username,password,phone,age test1,111111,18600000001,21 test2,222222,18600000002,22 test3,333333,18600000003,23 \u800c\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u6307\u5b9a\u53c2\u6570\u65f6\uff0c\u53ef\u4ee5\u53ea\u4f7f\u7528\u90e8\u5206\u53c2\u6570\uff0c\u5e76\u4e14\u53c2\u6570\u987a\u5e8f\u65e0\u9700\u4e0e CSV \u6587\u4ef6\u4e2d\u53c2\u6570\u540d\u79f0\u7684\u987a\u5e8f\u4e00\u81f4\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : phone-username : ${P(account.csv)}","title":"\u5173\u8054\u53c2\u6570 & \u5f15\u7528 CSV \u6587\u4ef6"},{"location":"prepare/parameters/#_6","text":"\u5bf9\u4e8e\u6ca1\u6709\u73b0\u6210\u53c2\u6570\u5217\u8868\uff0c\u6216\u8005\u9700\u8981\u66f4\u7075\u6d3b\u7684\u65b9\u5f0f\u52a8\u6001\u751f\u6210\u53c2\u6570\u7684\u60c5\u51b5\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728 debugtalk.py \u4e2d\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5e76\u5728 YAML/JSON \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u65b9\u5f0f\u3002 \u4f8b\u5982\uff0c\u82e5\u9700\u5bf9 user_id \u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u53c2\u6570\u53d6\u503c\u8303\u56f4\u4e3a 1001\uff5e1004\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u8fd4\u56de\u53c2\u6570\u5217\u8868\u3002 def get_user_id (): return [ { \"user_id\" : 1001 }, { \"user_id\" : 1002 }, { \"user_id\" : 1003 }, { \"user_id\" : 1004 } ] \u7136\u540e\uff0c\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u6765\u6307\u5b9a\u6570\u636e\u6e90\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : user_id : ${get_user_id()} \u53e6\u5916\uff0c\u901a\u8fc7\u51fd\u6570\u7684\u4f20\u53c2\u673a\u5236\uff0c\u8fd8\u53ef\u4ee5\u5b9e\u73b0\u66f4\u7075\u6d3b\u7684\u53c2\u6570\u751f\u6210\u529f\u80fd\uff0c\u5728\u8c03\u7528\u51fd\u6570\u65f6\u6307\u5b9a\u9700\u8981\u751f\u6210\u7684\u53c2\u6570\u4e2a\u6570\u3002","title":"\u72ec\u7acb\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570"},{"location":"prepare/parameters/#_7","text":"\u5bf9\u4e8e\u5177\u6709\u5173\u8054\u6027\u7684\u591a\u4e2a\u53c2\u6570\uff0c\u5b9e\u73b0\u65b9\u5f0f\u4e5f\u7c7b\u4f3c\u3002 \u4f8b\u5982\uff0c\u5728 debugtalk.py \u4e2d\u5b9a\u4e49\u51fd\u6570 get_account\uff0c\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u8d26\u53f7\u5bc6\u7801\u53c2\u6570\u5217\u8868\u3002 def get_account ( num ): accounts = [] for index in range ( 1 , num + 1 ): accounts . append ( { \"username\" : \"user %s \" % index , \"password\" : str ( index ) * 6 }, ) return accounts \u90a3\u4e48\u5728 YAML/JSON \u7684 parameters \u4e2d\u5c31\u53ef\u4ee5\u8c03\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u751f\u6210\u6307\u5b9a\u6570\u91cf\u7684\u53c2\u6570\u5217\u8868\u3002 config : name : \"demo\" testcases : testcase1_name : testcase : /path/to/testcase1 parameters : username-password : ${get_account(10)} \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728\u81ea\u5b9a\u4e49\u51fd\u6570\u4e2d\uff0c\u751f\u6210\u7684\u53c2\u6570\u5217\u8868\u5fc5\u987b\u4e3a list of dict \u7684\u6570\u636e\u7ed3\u6784\uff0c\u8be5\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u4e0e CSV \u6587\u4ef6\u7684\u5904\u7406\u673a\u5236\u4fdd\u6301\u4e00\u81f4\u3002","title":"\u5173\u8054\u53c2\u6570 & \u5f15\u7528\u81ea\u5b9a\u4e49\u51fd\u6570"},{"location":"prepare/parameters/#_8","text":"\u5b8c\u6210\u4ee5\u4e0a\u53c2\u6570\u5b9a\u4e49\u548c\u6570\u636e\u6e90\u51c6\u5907\u5de5\u4f5c\u4e4b\u540e\uff0c\u53c2\u6570\u5316\u8fd0\u884c\u4e0e\u666e\u901a\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u5b8c\u5168\u4e00\u81f4\u3002 \u91c7\u7528 hrun \u547d\u4ee4\u8fd0\u884c\u81ea\u52a8\u5316\u6d4b\u8bd5\uff1a $ hrun tests/data/demo_parameters.yml \u91c7\u7528 locusts \u547d\u4ee4\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5\uff1a $ locusts -f tests/data/demo_parameters.yml \u533a\u522b\u5728\u4e8e\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u65f6\u904d\u5386\u4e00\u904d\u540e\u4f1a\u7ec8\u6b62\u6267\u884c\uff0c\u6027\u80fd\u6d4b\u8bd5\u65f6\u6bcf\u4e2a\u5e76\u53d1\u7528\u6237\u90fd\u4f1a\u5faa\u73af\u904d\u5386\u6240\u6709\u53c2\u6570\u3002","title":"\u53c2\u6570\u5316\u8fd0\u884c"},{"location":"prepare/parameters/#_9","text":"\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u83b7\u53d6 token \u7684 \u6d4b\u8bd5\u7528\u4f8b \u3002 \u70b9\u51fb\u67e5\u770b YAML \u6d4b\u8bd5\u7528\u4f8b - config : name : get token base_url : http://127.0.0.1:5000 variables : device_sn : ${gen_random_string(15)} os_platform : 'ios' app_version : '2.8.6' - test : name : get token with $device_sn, $os_platform, $app_version request : headers : Content-Type : application/json User-Agent : python-requests/2.18.4 app_version : $app_version device_sn : $device_sn os_platform : $os_platform json : sign : ${get_sign($device_sn, $os_platform, $app_version)} method : POST url : /api/get-token extract : token : content.token validate : - eq : [ status_code , 200 ] - eq : [ headers.Content-Type , application/json ] - eq : [ content.success , true ] \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528 device_sn\u3001app_version \u548c os_platform \u8fd9\u4e09\u4e2a\u53c2\u6570\u6765\u8fdb\u884c\u53c2\u6570\u5316\u6570\u636e\u9a71\u52a8\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a testsuite \uff0c\u5e76\u4e14\u8fdb\u884c\u53c2\u6570\u5316\u914d\u7f6e\u3002 config : name : get token with parameters testcases : get token with $user_agent, $app_version, $os_platform : testcase : demo-testcase-get-token.yml parameters : user_agent : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ] app_version : ${P(app_version.csv)} os_platform : ${get_os_platform()} \u5176\u4e2d\uff0c user_agent \u4f7f\u7528\u4e86\u76f4\u63a5\u6307\u5b9a\u53c2\u6570\u5217\u8868\u7684\u5f62\u5f0f\u3002 app_version \u901a\u8fc7 CSV \u6587\u4ef6\u8fdb\u884c\u53c2\u6570\u914d\u7f6e\uff0c\u5bf9\u5e94\u7684\u6587\u4ef6\u5185\u5bb9\u4e3a\uff1a app_version 2.8.5 2.8.6 os_platform \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570\u7684\u5f62\u5f0f\u751f\u6210\u53c2\u6570\u5217\u8868\uff0c\u5bf9\u5e94\u7684\u51fd\u6570\u5185\u5bb9\u4e3a\uff1a def get_os_platform (): return [ { \"os_platform\" : \"ios\" }, { \"os_platform\" : \"android\" } ] \u90a3\u4e48\uff0c\u7ecf\u8fc7\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\uff0c\u5e94\u8be5\u603b\u5171\u6709 3*2*2=12 \u79cd\u53c2\u6570\u7ec4\u5408\u60c5\u51b5\u3002 \u70b9\u51fb\u67e5\u770b\u5b8c\u6574\u8fd0\u884c\u65e5\u5fd7 $ hrun docs/data/demo-parameters-get-token.yml INFO Start to run testcase: get token with iOS/10.1, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.66 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.026s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 10.76 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.012s OK INFO Start to run testcase: get token with iOS/10.1, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.49 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.39 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.04 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 3.44 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.004s OK INFO Start to run testcase: get token with iOS/10.2, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.03 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.005s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, ios get token with PBJda7SXM2ReWlu, ios, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.14 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.5, android get token with PBJda7SXM2ReWlu, android, 2.8.5 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 7.62 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.010s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, ios get token with PBJda7SXM2ReWlu, ios, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 4.88 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.006s OK INFO Start to run testcase: get token with iOS/10.3, 2.8.6, android get token with PBJda7SXM2ReWlu, android, 2.8.6 INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 5.41 ms, response_length: 46 bytes . ---------------------------------------------------------------------- Ran 1 test in 0.008s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1551950193.html","title":"\u6848\u4f8b\u6f14\u793a"},{"location":"prepare/project-structure/","text":"\u6587\u4ef6\u7c7b\u578b\b\u8bf4\u660e \u00b6 \u5728 HttpRunner \u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u4e2d\uff0c\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u51e0\u7c7b\u6587\u4ef6\uff1a YAML/JSON \uff08\u5fc5\u987b\uff09\uff1a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff0c\u5b58\u50a8\u63a5\u53e3\u6d4b\u8bd5\u76f8\u5173\u4fe1\u606f debugtalk.py \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u4e2d\u903b\u8f91\u8fd0\u7b97\u8f85\u52a9\u51fd\u6570 \u8be5\u6587\u4ef6\u5b58\u5728\u65f6\uff0c\u5c06\u4f5c\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\u5b9a\u4f4d\u6807\u8bb0\uff0c\u5176\u6240\u5728\u76ee\u5f55\u5373\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8be5\u6587\u4ef6\u4e0d\u5b58\u5728\u65f6\uff0c\u8fd0\u884c\u6d4b\u8bd5\u7684\u6240\u5728\u8def\u5f84\uff08 CWD \uff09\u5c06\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u7684\u76f8\u5bf9\u8def\u5f84\uff08\u4f8b\u5982 .csv \uff09\u5747\u9700\u57fa\u4e8e\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8fd0\u884c\u6d4b\u8bd5\u540e\uff0c\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u5939\uff08 reports \uff09\u4f1a\u751f\u6210\u5728\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 .env \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u73af\u5883\u53d8\u91cf\uff0c\u901a\u5e38\u7528\u4e8e\u5b58\u50a8\u9879\u76ee\u654f\u611f\u4fe1\u606f .csv \uff08\u53ef\u9009\uff09\uff1a\u9879\u76ee\u6570\u636e\u6587\u4ef6\uff0c\u7528\u4e8e\u8fdb\u884c\u6570\u636e\u9a71\u52a8 reports \uff1a\u9ed8\u8ba4\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u7684\u5b58\u50a8\u6587\u4ef6\u5939 \u9879\u76ee\u6587\u4ef6\u7ed3\u6784 \u00b6 \u5bf9\u4e8e\u63a5\u53e3\u6570\u6bd4\u8f83\u5c11\uff0c\u6216\u8005\u6d4b\u8bd5\u573a\u666f\u6bd4\u8f83\u7b80\u5355\u7684\u9879\u76ee\uff0c\u7ec4\u7ec7\u6d4b\u8bd5\u7528\u4f8b\u65f6\u65e0\u9700\u5206\u5c42\u3002\u5728\u6b64\u79cd\u60c5\u51b5\u4e0b\uff0c\u9879\u76ee\u6587\u4ef6\u7684\u76ee\u5f55\u7ed3\u6784\u6ca1\u6709\u4efb\u4f55\u8981\u6c42\uff0c\u5728\u9879\u76ee\u4e2d\u53ea\u9700\u8981\b\u4e00\u5806 YAML/JSON \u6587\u4ef6\u5373\u53ef\uff0c\u6bcf\u4e00\u4e2a\u6587\u4ef6\u5355\u72ec\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff1b\u6839\u636e\u9700\u8981\uff0c\u9879\u76ee\u4e2d\u53ef\u80fd\u8fd8\u4f1a\u6709 debugtalk.py \u3001 .env \u7b49\u6587\u4ef6\u3002 \u63a8\u8350\u7684\u9879\u76ee\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u793a\u4f8b\u5982\u4e0b\uff1a $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 reports \u251c\u2500\u2500 testcase1.yml \u2514\u2500\u2500 testcase2.json","title":"\u9879\u76ee\u6587\u4ef6\u7ec4\u7ec7"},{"location":"prepare/project-structure/#_1","text":"\u5728 HttpRunner \u81ea\u52a8\u5316\u6d4b\u8bd5\u9879\u76ee\u4e2d\uff0c\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u51e0\u7c7b\u6587\u4ef6\uff1a YAML/JSON \uff08\u5fc5\u987b\uff09\uff1a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff0c\u5b58\u50a8\u63a5\u53e3\u6d4b\u8bd5\u76f8\u5173\u4fe1\u606f debugtalk.py \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u4e2d\u903b\u8f91\u8fd0\u7b97\u8f85\u52a9\u51fd\u6570 \u8be5\u6587\u4ef6\u5b58\u5728\u65f6\uff0c\u5c06\u4f5c\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\u5b9a\u4f4d\u6807\u8bb0\uff0c\u5176\u6240\u5728\u76ee\u5f55\u5373\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8be5\u6587\u4ef6\u4e0d\u5b58\u5728\u65f6\uff0c\u8fd0\u884c\u6d4b\u8bd5\u7684\u6240\u5728\u8def\u5f84\uff08 CWD \uff09\u5c06\u88ab\u89c6\u4e3a\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u7684\u76f8\u5bf9\u8def\u5f84\uff08\u4f8b\u5982 .csv \uff09\u5747\u9700\u57fa\u4e8e\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 \u8fd0\u884c\u6d4b\u8bd5\u540e\uff0c\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u5939\uff08 reports \uff09\u4f1a\u751f\u6210\u5728\u9879\u76ee\u5de5\u7a0b\u6839\u76ee\u5f55 .env \uff08\u53ef\u9009\uff09\uff1a\u5b58\u50a8\u9879\u76ee\u73af\u5883\u53d8\u91cf\uff0c\u901a\u5e38\u7528\u4e8e\u5b58\u50a8\u9879\u76ee\u654f\u611f\u4fe1\u606f .csv \uff08\u53ef\u9009\uff09\uff1a\u9879\u76ee\u6570\u636e\u6587\u4ef6\uff0c\u7528\u4e8e\u8fdb\u884c\u6570\u636e\u9a71\u52a8 reports \uff1a\u9ed8\u8ba4\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u7684\u5b58\u50a8\u6587\u4ef6\u5939","title":"\u6587\u4ef6\u7c7b\u578b\b\u8bf4\u660e"},{"location":"prepare/project-structure/#_2","text":"\u5bf9\u4e8e\u63a5\u53e3\u6570\u6bd4\u8f83\u5c11\uff0c\u6216\u8005\u6d4b\u8bd5\u573a\u666f\u6bd4\u8f83\u7b80\u5355\u7684\u9879\u76ee\uff0c\u7ec4\u7ec7\u6d4b\u8bd5\u7528\u4f8b\u65f6\u65e0\u9700\u5206\u5c42\u3002\u5728\u6b64\u79cd\u60c5\u51b5\u4e0b\uff0c\u9879\u76ee\u6587\u4ef6\u7684\u76ee\u5f55\u7ed3\u6784\u6ca1\u6709\u4efb\u4f55\u8981\u6c42\uff0c\u5728\u9879\u76ee\u4e2d\u53ea\u9700\u8981\b\u4e00\u5806 YAML/JSON \u6587\u4ef6\u5373\u53ef\uff0c\u6bcf\u4e00\u4e2a\u6587\u4ef6\u5355\u72ec\u5bf9\u5e94\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\uff1b\u6839\u636e\u9700\u8981\uff0c\u9879\u76ee\u4e2d\u53ef\u80fd\u8fd8\u4f1a\u6709 debugtalk.py \u3001 .env \u7b49\u6587\u4ef6\u3002 \u63a8\u8350\u7684\u9879\u76ee\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u793a\u4f8b\u5982\u4e0b\uff1a $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 reports \u251c\u2500\u2500 testcase1.yml \u2514\u2500\u2500 testcase2.json","title":"\u9879\u76ee\u6587\u4ef6\u7ed3\u6784"},{"location":"prepare/record/","text":"\u4e3a\u4e86\u7b80\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7f16\u5199\u5de5\u4f5c\uff0cHttpRunner \u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u7684\u529f\u80fd\uff0c\u5bf9\u5e94\u7684\u8f6c\u6362\u5de5\u5177\u4e3a\u4e00\u4e2a\u72ec\u7acb\u7684\u9879\u76ee\uff1a har2case \u3002 \u7b80\u5355\u6765\u8bf4\uff0c\u5c31\u662f\u5f53\u524d\u4e3b\u6d41\u7684\u6293\u5305\u5de5\u5177\u548c\u6d4f\u89c8\u5668\u90fd\u652f\u6301\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a\u6807\u51c6\u901a\u7528\u7684 HAR \u683c\u5f0f\uff08HTTP Archive\uff09\uff0c\u7136\u540e HttpRunner \u5b9e\u73b0\u4e86\u5c06 HAR \u683c\u5f0f\u7684\u6570\u636e\u5305\u8f6c\u6362\u4e3a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u529f\u80fd\u3002 \u83b7\u53d6 HAR \u6570\u636e\u5305 \u00b6 \u5728\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\u3002\u5728 Charles Proxy \u4e2d\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff0c\u9009\u4e2d\u9700\u8981\u8f6c\u6362\u7684\u63a5\u53e3\uff08\u53ef\u591a\u9009\u6216\u5168\u9009\uff09\uff0c\u70b9\u51fb\u53f3\u952e\uff0c\u5728\u60ac\u6d6e\u7684\u83dc\u5355\u76ee\u5f55\u4e2d\u70b9\u51fb\u3010Export...\u3011\uff0c\u683c\u5f0f\u9009\u62e9 HTTP Archive(.har) \u540e\u4fdd\u5b58\u5373\u53ef\uff1b\u5047\u8bbe\u6211\u4eec\u4fdd\u5b58\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo.har\u3002 \u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c har2case \u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har INFO:root:Start to generate testcase. INFO:root:dump testcase to JSON format. INFO:root:Generate JSON testcase successfully: docs/data/demo-quickstart.json \u52a0\u4e0a -2y / --to-yml \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002","title":"\u5f55\u5236\u751f\u6210\u7528\u4f8b"},{"location":"prepare/record/#har","text":"\u5728\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u4e4b\u524d\uff0c\u9700\u8981\u5148\u5c06\u6293\u53d6\u5f97\u5230\u7684\u6570\u636e\u5305\u5bfc\u51fa\u4e3a HAR \u683c\u5f0f\u7684\u6587\u4ef6\u3002\u5728 Charles Proxy \u4e2d\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff0c\u9009\u4e2d\u9700\u8981\u8f6c\u6362\u7684\u63a5\u53e3\uff08\u53ef\u591a\u9009\u6216\u5168\u9009\uff09\uff0c\u70b9\u51fb\u53f3\u952e\uff0c\u5728\u60ac\u6d6e\u7684\u83dc\u5355\u76ee\u5f55\u4e2d\u70b9\u51fb\u3010Export...\u3011\uff0c\u683c\u5f0f\u9009\u62e9 HTTP Archive(.har) \u540e\u4fdd\u5b58\u5373\u53ef\uff1b\u5047\u8bbe\u6211\u4eec\u4fdd\u5b58\u7684\u6587\u4ef6\u540d\u79f0\u4e3a demo.har\u3002","title":"\u83b7\u53d6 HAR \u6570\u636e\u5305"},{"location":"prepare/record/#_1","text":"\u7136\u540e\uff0c\u5728\u547d\u4ee4\u884c\u7ec8\u7aef\u4e2d\u8fd0\u884c har2case \u547d\u4ee4\uff0c\u5373\u53ef\u5c06 demo.har \u8f6c\u6362\u4e3a HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002 \u4f7f\u7528 har2case \u8f6c\u6362\u811a\u672c\u65f6\u9ed8\u8ba4\u8f6c\u6362\u4e3a JSON \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har INFO:root:Start to generate testcase. INFO:root:dump testcase to JSON format. INFO:root:Generate JSON testcase successfully: docs/data/demo-quickstart.json \u52a0\u4e0a -2y / --to-yml \u53c2\u6570\u540e\u8f6c\u6362\u4e3a YAML \u683c\u5f0f\u3002 $ har2case docs/data/demo-quickstart.har -2y INFO:root:Start to generate testcase. INFO:root:dump testcase to YAML format. INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml \u4e24\u79cd\u683c\u5f0f\u5b8c\u5168\u7b49\u4ef7\uff0cYAML \u683c\u5f0f\u66f4\u7b80\u6d01\uff0cJSON \u683c\u5f0f\u652f\u6301\u7684\u5de5\u5177\u66f4\u4e30\u5bcc\uff0c\u5927\u5bb6\u53ef\u6839\u636e\u4e2a\u4eba\u559c\u597d\u8fdb\u884c\u9009\u62e9\u3002","title":"\u8f6c\u6362\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b"},{"location":"prepare/request-hook/","text":"\u6982\u8ff0 \u00b6 HttpRunner \u4ece 1.4.5 \u7248\u672c\u5f00\u59cb\u5b9e\u73b0\u4e86\u5168\u65b0\u7684 hook \u673a\u5236\uff0c\u53ef\u4ee5\u5728\u8bf7\u6c42\u524d\u548c\u8bf7\u6c42\u540e\u8c03\u7528\u94a9\u5b50\u51fd\u6570\u3002 \u8c03\u7528 hook \u51fd\u6570 \u00b6 hook \u673a\u5236\u5206\u4e3a\u4e24\u4e2a\u5c42\u7ea7\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09 \u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09 \u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09 \u00b6 \u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u7684 config \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u5f00\u59cb\u6267\u884c\u524d\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\u3002 teardown_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u7ed3\u675f\u6267\u884c\u540e\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\u3002 - config : name : basic test with httpbin request : base_url : http://127.0.0.1:3458/ setup_hooks : - ${hook_print(setup)} teardown_hooks : - ${hook_print(teardown)} \u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09 \u00b6 \u5728 YAML/JSON \u6d4b\u8bd5\u6b65\u9aa4\u7684 test \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u8bf7\u6c42\u7684 request \u5185\u5bb9\u8fdb\u884c\u9884\u5904\u7406\u3002 teardown_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u54cd\u5e94\u7684 response \u8fdb\u884c\u4fee\u6539\uff0c\u4f8b\u5982\u8fdb\u884c\u52a0\u89e3\u5bc6\u7b49\u5904\u7406\u3002 \"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]} ], \"setup_hooks\" : [ \"${setup_hook_prepare_kwargs($request)}\" , \"${setup_hook_httpntlmauth($request)}\" ], \"teardown_hooks\" : [ \"${teardown_hook_sleep_N_secs($response, 2)}\" ] } \u7f16\u5199 hook \u51fd\u6570 \u00b6 hook \u51fd\u6570\u7684\u5b9a\u4e49\u653e\u7f6e\u5728\u9879\u76ee\u7684 debugtalk.py \u4e2d\uff0c\u5728 YAML/JSON \u4e2d\u8c03\u7528 hook \u51fd\u6570\u4ecd\u7136\u662f\u91c7\u7528 ${func($a, $b)} \u7684\u5f62\u5f0f\u3002 \u5bf9\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u4e0e YAML/JSON \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u5b8c\u5168\u76f8\u540c\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49\u53c2\u6570\u4f20\u53c2\u7684\u5f62\u5f0f\u6765\u5b9e\u73b0\u7075\u6d3b\u5e94\u7528\u3002 def hook_print ( msg ): print ( msg ) \u5bf9\u4e8e\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165\u4e0e\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u76f8\u5173\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 $request \u548c\u54cd\u5e94\u7684 $response \uff0c\u7528\u4e8e\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u7075\u6d3b\u5e94\u7528\u3002 setup_hooks \u00b6 \u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 setup_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $request \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 request \u7684\u5168\u90e8\u5185\u5bb9\u3002\u56e0\u4e3a request \u662f\u53ef\u53d8\u53c2\u6570\u7c7b\u578b\uff08dict\uff09\uff0c\u56e0\u6b64\u8be5\u51fd\u6570\u53c2\u6570\u4e3a\u5f15\u7528\u4f20\u9012\uff0c\u5f53\u6211\u4eec\u9700\u8981\u5bf9\u8bf7\u6c42\u53c2\u6570\u8fdb\u884c\u9884\u5904\u7406\u65f6\u5c24\u5176\u6709\u7528\u3002 e.g. def setup_hook_prepare_kwargs ( request ): if request [ \"method\" ] == \"POST\" : content_type = request . get ( \"headers\" , {}) . get ( \"content-type\" ) if content_type and \"data\" in request : # if request content-type is application/json, request data should be dumped if content_type . startswith ( \"application/json\" ) and isinstance ( request [ \"data\" ], ( dict , list )): request [ \"data\" ] = json . dumps ( request [ \"data\" ]) if isinstance ( request [ \"data\" ], str ): request [ \"data\" ] = request [ \"data\" ] . encode ( 'utf-8' ) def setup_hook_httpntlmauth ( request ): if \"httpntlmauth\" in request : from requests_ntlm import HttpNtlmAuth auth_account = request . pop ( \"httpntlmauth\" ) request [ \"auth\" ] = HttpNtlmAuth ( auth_account [ \"username\" ], auth_account [ \"password\" ]) \u901a\u8fc7\u4e0a\u8ff0\u7684 setup_hook_prepare_kwargs \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0\u6839\u636e\u8bf7\u6c42\u65b9\u6cd5\u548c\u8bf7\u6c42\u7684 Content-Type \u6765\u5bf9\u8bf7\u6c42\u7684 data \u8fdb\u884c\u52a0\u5de5\u5904\u7406\uff1b\u901a\u8fc7 setup_hook_httpntlmauth \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0 HttpNtlmAuth \u6743\u9650\u6388\u6743\u3002 teardown_hooks \u00b6 \u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 teardown_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $response \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u8bf7\u6c42\u7684\u54cd\u5e94\u5b9e\u4f8b\uff08requests.Response\uff09\u3002 e.g. def teardown_hook_sleep_N_secs ( response , n_secs ): \"\"\" sleep n seconds after request \"\"\" if response . status_code == 200 : time . sleep ( 0.1 ) else : time . sleep ( n_secs ) \u901a\u8fc7\u4e0a\u8ff0\u7684 teardown_hook_sleep_N_secs \u51fd\u6570\uff0c\u53ef\u4ee5\u6839\u636e\u63a5\u53e3\u54cd\u5e94\u7684\u72b6\u6001\u7801\u6765\u8fdb\u884c\u4e0d\u540c\u65f6\u95f4\u7684\u5ef6\u8fdf\u7b49\u5f85\u3002 \u53e6\u5916\uff0c\u5728 teardown_hooks \u51fd\u6570\u4e2d\u8fd8\u53ef\u4ee5\u5bf9 response \u8fdb\u884c\u4fee\u6539\u3002\u5f53\u6211\u4eec\u9700\u8981\u5148\u5bf9\u54cd\u5e94\u5185\u5bb9\u8fdb\u884c\u5904\u7406\uff08\u4f8b\u5982\u52a0\u89e3\u5bc6\u3001\u53c2\u6570\u8fd0\u7b97\uff09\uff0c\u518d\u8fdb\u884c\u53c2\u6570\u63d0\u53d6\uff08extract\uff09\u548c\u6821\u9a8c\uff08validate\uff09\u65f6\u5c24\u5176\u6709\u7528\u3002 \u4f8b\u5982\u5728\u4e0b\u9762\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u5728\u6267\u884c\u6d4b\u8bd5\u540e\uff0c\u901a\u8fc7 teardown_hooks \u51fd\u6570\u5c06\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u548c headers \u8fdb\u884c\u4e86\u4fee\u6539\uff0c\u7136\u540e\u518d\u8fdb\u884c\u4e86\u6821\u9a8c\u3002 - test : name : alter response request : url : /headers method : GET teardown_hooks : - ${alter_response($response)} validate : - eq : [ \"status_code\" , 500 ] - eq : [ \"headers.content-type\" , \"html/text\" ] def alter_response ( response ): response . status_code = 500 response . headers [ \"Content-Type\" ] = \"html/text\"","title":"hook\u673a\u5236"},{"location":"prepare/request-hook/#_1","text":"HttpRunner \u4ece 1.4.5 \u7248\u672c\u5f00\u59cb\u5b9e\u73b0\u4e86\u5168\u65b0\u7684 hook \u673a\u5236\uff0c\u53ef\u4ee5\u5728\u8bf7\u6c42\u524d\u548c\u8bf7\u6c42\u540e\u8c03\u7528\u94a9\u5b50\u51fd\u6570\u3002","title":"\u6982\u8ff0"},{"location":"prepare/request-hook/#hook","text":"hook \u673a\u5236\u5206\u4e3a\u4e24\u4e2a\u5c42\u7ea7\uff1a \u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09 \u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09","title":"\u8c03\u7528 hook \u51fd\u6570"},{"location":"prepare/request-hook/#testcase","text":"\u5728 YAML/JSON \u6d4b\u8bd5\u7528\u4f8b\u7684 config \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u5f00\u59cb\u6267\u884c\u524d\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\u3002 teardown_hooks: \u5728\u6574\u4e2a\u7528\u4f8b\u7ed3\u675f\u6267\u884c\u540e\u89e6\u53d1 hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\u3002 - config : name : basic test with httpbin request : base_url : http://127.0.0.1:3458/ setup_hooks : - ${hook_print(setup)} teardown_hooks : - ${hook_print(teardown)}","title":"\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\uff08testcase\uff09"},{"location":"prepare/request-hook/#teststep","text":"\u5728 YAML/JSON \u6d4b\u8bd5\u6b65\u9aa4\u7684 test \u4e2d\u65b0\u589e\u5173\u952e\u5b57 setup_hooks \u548c teardown_hooks \u3002 setup_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u8bf7\u6c42\u7684 request \u5185\u5bb9\u8fdb\u884c\u9884\u5904\u7406\u3002 teardown_hooks: \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c\uff1b\u4e5f\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u54cd\u5e94\u7684 response \u8fdb\u884c\u4fee\u6539\uff0c\u4f8b\u5982\u8fdb\u884c\u52a0\u89e3\u5bc6\u7b49\u5904\u7406\u3002 \"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]} ], \"setup_hooks\" : [ \"${setup_hook_prepare_kwargs($request)}\" , \"${setup_hook_httpntlmauth($request)}\" ], \"teardown_hooks\" : [ \"${teardown_hook_sleep_N_secs($response, 2)}\" ] }","title":"\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\uff08teststep\uff09"},{"location":"prepare/request-hook/#hook_1","text":"hook \u51fd\u6570\u7684\u5b9a\u4e49\u653e\u7f6e\u5728\u9879\u76ee\u7684 debugtalk.py \u4e2d\uff0c\u5728 YAML/JSON \u4e2d\u8c03\u7528 hook \u51fd\u6570\u4ecd\u7136\u662f\u91c7\u7528 ${func($a, $b)} \u7684\u5f62\u5f0f\u3002 \u5bf9\u4e8e\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u4e0e YAML/JSON \u4e2d\u81ea\u5b9a\u4e49\u7684\u51fd\u6570\u5b8c\u5168\u76f8\u540c\uff0c\u53ef\u901a\u8fc7\u81ea\u5b9a\u4e49\u53c2\u6570\u4f20\u53c2\u7684\u5f62\u5f0f\u6765\u5b9e\u73b0\u7075\u6d3b\u5e94\u7528\u3002 def hook_print ( msg ): print ( msg ) \u5bf9\u4e8e\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u5c42\u9762\u7684 hook \u51fd\u6570\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165\u4e0e\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u76f8\u5173\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 $request \u548c\u54cd\u5e94\u7684 $response \uff0c\u7528\u4e8e\u5b9e\u73b0\u66f4\u590d\u6742\u573a\u666f\u7684\u7075\u6d3b\u5e94\u7528\u3002","title":"\u7f16\u5199 hook \u51fd\u6570"},{"location":"prepare/request-hook/#setup_hooks","text":"\u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 setup_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $request \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 request \u7684\u5168\u90e8\u5185\u5bb9\u3002\u56e0\u4e3a request \u662f\u53ef\u53d8\u53c2\u6570\u7c7b\u578b\uff08dict\uff09\uff0c\u56e0\u6b64\u8be5\u51fd\u6570\u53c2\u6570\u4e3a\u5f15\u7528\u4f20\u9012\uff0c\u5f53\u6211\u4eec\u9700\u8981\u5bf9\u8bf7\u6c42\u53c2\u6570\u8fdb\u884c\u9884\u5904\u7406\u65f6\u5c24\u5176\u6709\u7528\u3002 e.g. def setup_hook_prepare_kwargs ( request ): if request [ \"method\" ] == \"POST\" : content_type = request . get ( \"headers\" , {}) . get ( \"content-type\" ) if content_type and \"data\" in request : # if request content-type is application/json, request data should be dumped if content_type . startswith ( \"application/json\" ) and isinstance ( request [ \"data\" ], ( dict , list )): request [ \"data\" ] = json . dumps ( request [ \"data\" ]) if isinstance ( request [ \"data\" ], str ): request [ \"data\" ] = request [ \"data\" ] . encode ( 'utf-8' ) def setup_hook_httpntlmauth ( request ): if \"httpntlmauth\" in request : from requests_ntlm import HttpNtlmAuth auth_account = request . pop ( \"httpntlmauth\" ) request [ \"auth\" ] = HttpNtlmAuth ( auth_account [ \"username\" ], auth_account [ \"password\" ]) \u901a\u8fc7\u4e0a\u8ff0\u7684 setup_hook_prepare_kwargs \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0\u6839\u636e\u8bf7\u6c42\u65b9\u6cd5\u548c\u8bf7\u6c42\u7684 Content-Type \u6765\u5bf9\u8bf7\u6c42\u7684 data \u8fdb\u884c\u52a0\u5de5\u5904\u7406\uff1b\u901a\u8fc7 setup_hook_httpntlmauth \u51fd\u6570\uff0c\u53ef\u4ee5\u5b9e\u73b0 HttpNtlmAuth \u6743\u9650\u6388\u6743\u3002","title":"setup_hooks"},{"location":"prepare/request-hook/#teardown_hooks","text":"\u5728\u6d4b\u8bd5\u6b65\u9aa4\u5c42\u9762\u7684 teardown_hooks \u51fd\u6570\u4e2d\uff0c\u9664\u4e86\u53ef\u4f20\u5165\u81ea\u5b9a\u4e49\u53c2\u6570\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f20\u5165 $response \uff0c\u8be5\u53c2\u6570\u5bf9\u5e94\u7740\u5f53\u524d\u8bf7\u6c42\u7684\u54cd\u5e94\u5b9e\u4f8b\uff08requests.Response\uff09\u3002 e.g. def teardown_hook_sleep_N_secs ( response , n_secs ): \"\"\" sleep n seconds after request \"\"\" if response . status_code == 200 : time . sleep ( 0.1 ) else : time . sleep ( n_secs ) \u901a\u8fc7\u4e0a\u8ff0\u7684 teardown_hook_sleep_N_secs \u51fd\u6570\uff0c\u53ef\u4ee5\u6839\u636e\u63a5\u53e3\u54cd\u5e94\u7684\u72b6\u6001\u7801\u6765\u8fdb\u884c\u4e0d\u540c\u65f6\u95f4\u7684\u5ef6\u8fdf\u7b49\u5f85\u3002 \u53e6\u5916\uff0c\u5728 teardown_hooks \u51fd\u6570\u4e2d\u8fd8\u53ef\u4ee5\u5bf9 response \u8fdb\u884c\u4fee\u6539\u3002\u5f53\u6211\u4eec\u9700\u8981\u5148\u5bf9\u54cd\u5e94\u5185\u5bb9\u8fdb\u884c\u5904\u7406\uff08\u4f8b\u5982\u52a0\u89e3\u5bc6\u3001\u53c2\u6570\u8fd0\u7b97\uff09\uff0c\u518d\u8fdb\u884c\u53c2\u6570\u63d0\u53d6\uff08extract\uff09\u548c\u6821\u9a8c\uff08validate\uff09\u65f6\u5c24\u5176\u6709\u7528\u3002 \u4f8b\u5982\u5728\u4e0b\u9762\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u5728\u6267\u884c\u6d4b\u8bd5\u540e\uff0c\u901a\u8fc7 teardown_hooks \u51fd\u6570\u5c06\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u548c headers \u8fdb\u884c\u4e86\u4fee\u6539\uff0c\u7136\u540e\u518d\u8fdb\u884c\u4e86\u6821\u9a8c\u3002 - test : name : alter response request : url : /headers method : GET teardown_hooks : - ${alter_response($response)} validate : - eq : [ \"status_code\" , 500 ] - eq : [ \"headers.content-type\" , \"html/text\" ] def alter_response ( response ): response . status_code = 500 response . headers [ \"Content-Type\" ] = \"html/text\"","title":"teardown_hooks"},{"location":"prepare/security/","text":"\u80cc\u666f \u00b6 \u5f88\u591a\u65f6\u5019\u9879\u76ee\u4ee3\u7801\u5728\u8fd0\u884c\u65f6\u9700\u8981\u4f7f\u7528\u5230\u8d26\u53f7\u3001\u5bc6\u7801\u3001key\u7b49\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u4f46\u662f\u4ece\u4fe1\u606f\u5b89\u5168\u7684\u89d2\u5ea6\u8003\u8651\uff0c\u6211\u4eec\u662f\u4e0d\u80fd\u5c06\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u63d0\u4ea4\u5230\u4ee3\u7801\u4ed3\u5e93\u7684\uff0c\u4e3b\u8981\u539f\u56e0\u6709\u4e24\u4e2a\uff1a \u52a0\u5f3a\u6743\u9650\u7ba1\u63a7\uff1a\u53c2\u4e0e\u9879\u76ee\u7684\u5f00\u53d1\u4eba\u5458\u53ef\u80fd\u4f1a\u6709\u5f88\u591a\uff0c\u5927\u5bb6\u90fd\u6709\u8bfb\u53d6\u4ee3\u7801\u4ed3\u5e93\u7684\u6743\u9650\uff0c\u4f46\u662f\u50cf key \u8fd9\u7c7b\u6781\u5ea6\u654f\u611f\u7684\u4fe1\u606f\u4e0d\u5e94\u8be5\u6240\u6709\u4eba\u90fd\u6709\u6743\u9650\u83b7\u53d6\uff1b \u51cf\u5c11\u4ee3\u7801\u6cc4\u6f0f\u7684\u5371\u5bb3\u6027\uff1a\u5047\u5982\u4ee3\u7801\u51fa\u73b0\u6cc4\u6f0f\uff0c\u654f\u611f\u6570\u636e\u4fe1\u606f\u4e0d\u5e94\u8be5\u4e5f\u540c\u65f6\u6cc4\u6f0f\u3002 \u89e3\u51b3\u65b9\u6848 \u00b6 \u90a3\u4ee3\u7801\u90e8\u7f72\u5230\u670d\u52a1\u5668\u6216 Jenkins \u6267\u884c\u673a\u540e\uff0c\u8fd0\u884c\u65f6\u8981\u4f7f\u7528\u5230\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u8be5\u600e\u4e48\u64cd\u4f5c\u5462\uff1f \u63a8\u8350\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff1a \u5bf9\u670d\u52a1\u5668\u8fdb\u884c\u6743\u9650\u7ba1\u63a7\uff0c\u53ea\u6709\u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\u624d\u6709\u767b\u5f55\u670d\u52a1\u5668\u7684\u6743\u9650\uff1b \u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\uff1a\u5728\u8fd0\u884c\u7684\u673a\u5668\u4e0a\u5c06\u654f\u611f\u6570\u636e\u8bbe\u7f6e\u5230\u7cfb\u7edf\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff1b \u666e\u901a\u5f00\u53d1\u4eba\u5458\uff1a\u53ea\u9700\u8981\u77e5\u9053\u654f\u611f\u4fe1\u606f\u7684\u53d8\u91cf\u540d\u79f0\uff0c\u5728\u4ee3\u7801\u4e2d\u901a\u8fc7\u8bfb\u53d6\u73af\u5883\u53d8\u91cf\u7684\u65b9\u5f0f\u83b7\u53d6\u654f\u611f\u6570\u636e\u3002 \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\uff09\u548c\u4f7f\u7528\u654f\u611f\u6570\u636e\uff08\u5f15\u7528\u73af\u5883\u53d8\u91cf\uff09\u7684\u5177\u4f53\u65b9\u6cd5\uff0c\u53ef\u53c2\u8003 \u73af\u5883\u53d8\u91cf \u4f7f\u7528\u8bf4\u660e\u6587\u6863\u3002","title":"\u4fe1\u606f\u5b89\u5168"},{"location":"prepare/security/#_1","text":"\u5f88\u591a\u65f6\u5019\u9879\u76ee\u4ee3\u7801\u5728\u8fd0\u884c\u65f6\u9700\u8981\u4f7f\u7528\u5230\u8d26\u53f7\u3001\u5bc6\u7801\u3001key\u7b49\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u4f46\u662f\u4ece\u4fe1\u606f\u5b89\u5168\u7684\u89d2\u5ea6\u8003\u8651\uff0c\u6211\u4eec\u662f\u4e0d\u80fd\u5c06\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u63d0\u4ea4\u5230\u4ee3\u7801\u4ed3\u5e93\u7684\uff0c\u4e3b\u8981\u539f\u56e0\u6709\u4e24\u4e2a\uff1a \u52a0\u5f3a\u6743\u9650\u7ba1\u63a7\uff1a\u53c2\u4e0e\u9879\u76ee\u7684\u5f00\u53d1\u4eba\u5458\u53ef\u80fd\u4f1a\u6709\u5f88\u591a\uff0c\u5927\u5bb6\u90fd\u6709\u8bfb\u53d6\u4ee3\u7801\u4ed3\u5e93\u7684\u6743\u9650\uff0c\u4f46\u662f\u50cf key \u8fd9\u7c7b\u6781\u5ea6\u654f\u611f\u7684\u4fe1\u606f\u4e0d\u5e94\u8be5\u6240\u6709\u4eba\u90fd\u6709\u6743\u9650\u83b7\u53d6\uff1b \u51cf\u5c11\u4ee3\u7801\u6cc4\u6f0f\u7684\u5371\u5bb3\u6027\uff1a\u5047\u5982\u4ee3\u7801\u51fa\u73b0\u6cc4\u6f0f\uff0c\u654f\u611f\u6570\u636e\u4fe1\u606f\u4e0d\u5e94\u8be5\u4e5f\u540c\u65f6\u6cc4\u6f0f\u3002","title":"\u80cc\u666f"},{"location":"prepare/security/#_2","text":"\u90a3\u4ee3\u7801\u90e8\u7f72\u5230\u670d\u52a1\u5668\u6216 Jenkins \u6267\u884c\u673a\u540e\uff0c\u8fd0\u884c\u65f6\u8981\u4f7f\u7528\u5230\u8fd9\u4e9b\u654f\u611f\u6570\u636e\u4fe1\u606f\uff0c\u8be5\u600e\u4e48\u64cd\u4f5c\u5462\uff1f \u63a8\u8350\u7684\u64cd\u4f5c\u65b9\u5f0f\u4e3a\uff1a \u5bf9\u670d\u52a1\u5668\u8fdb\u884c\u6743\u9650\u7ba1\u63a7\uff0c\u53ea\u6709\u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\u624d\u6709\u767b\u5f55\u670d\u52a1\u5668\u7684\u6743\u9650\uff1b \u8fd0\u7ef4\u4eba\u5458\uff08\u6216\u8005\u6838\u5fc3\u5f00\u53d1\u4eba\u5458\uff09\uff1a\u5728\u8fd0\u884c\u7684\u673a\u5668\u4e0a\u5c06\u654f\u611f\u6570\u636e\u8bbe\u7f6e\u5230\u7cfb\u7edf\u7684\u73af\u5883\u53d8\u91cf\u4e2d\uff1b \u666e\u901a\u5f00\u53d1\u4eba\u5458\uff1a\u53ea\u9700\u8981\u77e5\u9053\u654f\u611f\u4fe1\u606f\u7684\u53d8\u91cf\u540d\u79f0\uff0c\u5728\u4ee3\u7801\u4e2d\u901a\u8fc7\u8bfb\u53d6\u73af\u5883\u53d8\u91cf\u7684\u65b9\u5f0f\u83b7\u53d6\u654f\u611f\u6570\u636e\u3002 \u5b58\u50a8\u654f\u611f\u6570\u636e\uff08\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\uff09\u548c\u4f7f\u7528\u654f\u611f\u6570\u636e\uff08\u5f15\u7528\u73af\u5883\u53d8\u91cf\uff09\u7684\u5177\u4f53\u65b9\u6cd5\uff0c\u53ef\u53c2\u8003 \u73af\u5883\u53d8\u91cf \u4f7f\u7528\u8bf4\u660e\u6587\u6863\u3002","title":"\u89e3\u51b3\u65b9\u6848"},{"location":"prepare/testcase-layer/","text":"\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b \u00b6 \u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9886\u57df\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u53ef\u7ef4\u62a4\u6027\u662f\u6781\u5176\u91cd\u8981\u7684\u56e0\u7d20\uff0c\u76f4\u63a5\u5173\u7cfb\u5230\u81ea\u52a8\u5316\u6d4b\u8bd5\u80fd\u5426\u6301\u7eed\u6709\u6548\u5730\u5728\u9879\u76ee\u4e2d\u5f00\u5c55\u3002 \u6982\u62ec\u6765\u8bf4\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\u7684\u6838\u5fc3\u662f\u5c06\u63a5\u53e3\u5b9a\u4e49\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u573a\u666f\u8fdb\u884c\u5206\u79bb\uff0c\u5355\u72ec\u8fdb\u884c\u63cf\u8ff0\u548c\u7ef4\u62a4\uff0c\u4ece\u800c\u5c3d\u53ef\u80fd\u5730\u51cf\u5c11\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7ef4\u62a4\u6210\u672c\u3002 \u903b\u8f91\u5173\u7cfb\u56fe\u5982\u4e0b\u6240\u793a\uff1a \u540c\u65f6\uff0c\u5f3a\u8c03\u5982\u4e0b\u51e0\u70b9\u6838\u5fc3\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684 \u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406 \u5982\u679c\u5bf9\u4e8e\u4e0a\u8ff0\u7b2c\u4e09\u70b9\u611f\u89c9\u96be\u4ee5\u7406\u89e3\uff0c\u4e0d\u59a8\u770b\u4e0b\u4e0a\u56fe\u4e2d\u7684\u793a\u4f8b\uff1a testcase1 \u4f9d\u8d56\u4e8e testcase2\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep12\uff09\u4e2d\u5bf9 testcase2 \u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e testcase1 \u5c31\u662f\u5b8c\u6574\u4e14\u53ef\u72ec\u7acb\u8fd0\u884c\u7684\uff1b \u5728 testsuite \u4e2d\uff0ctestcase1 \u4e0e testcase2 \u76f8\u4e92\u72ec\u7acb\uff0c\u8fd0\u884c\u987a\u5e8f\u5c31\u4e0d\u518d\u6709\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u4e86\u3002 \u5206\u5c42\u63cf\u8ff0\u8be6\u89e3 \u00b6 \u7406\u89e3\u4e86\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\uff0c\u63a5\u4e0b\u6765\u6211\u4eec\u518d\u6765\u770b\u4e0b\u5728\u5206\u5c42\u6a21\u578b\u4e0b\uff0c\u63a5\u53e3\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u3002 \u63a5\u53e3\u5b9a\u4e49\uff08API\uff09 \u00b6 \u4e3a\u4e86\u66f4\u597d\u5730\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u7ba1\u7406\uff0c\u63a8\u8350\u4f7f\u7528\u72ec\u7acb\u7684\u6587\u4ef6\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u5b58\u50a8\uff0c\u5373\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u63a5\u53e3\u63cf\u8ff0\u3002 \u63a5\u53e3\u5b9a\u4e49\u63cf\u8ff0\u7684\u4e3b\u8981\u5185\u5bb9\u5305\u62ec\uff1a name \u3001variables\u3001 request \u3001base_url\u3001validate \u7b49\uff0c\u5f62\u5f0f\u5982\u4e0b\uff1a name : get headers base_url : http://httpbin.org variables : expected_status_code : 200 request : url : /headers method : GET validate : - eq : [ \"status_code\" , $expected_status_code ] - eq : [ content.headers.Host , \"httpbin.org\" ] \u5176\u4e2d\uff0cname \u548c request \u90e8\u5206\u662f\u5fc5\u987b\u7684\uff0crequest \u4e2d\u7684\u63cf\u8ff0\u5f62\u5f0f\u4e0e requests.request \u5b8c\u5168\u76f8\u540c\u3002 \u53e6\u5916\uff0cAPI \u63cf\u8ff0\u9700\u8981\u5c3d\u91cf\u4fdd\u6301\u5b8c\u6574\uff0c\u505a\u5230\u53ef\u4ee5\u5355\u72ec\u8fd0\u884c\u3002\u5982\u679c\u5728\u63a5\u53e3\u63cf\u8ff0\u4e2d\u5b58\u5728\u53d8\u91cf\u5f15\u7528\u7684\u60c5\u51b5\uff0c\u53ef\u5728 variables \u4e2d\u5bf9\u53c2\u6570\u8fdb\u884c\u5b9a\u4e49\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5f88\u597d\u5730\u5b9e\u73b0\u5355\u4e2a\u63a5\u53e3\u7684\u8c03\u8bd5\u3002 $ hrun api/get_headers.yml INFO Start to run testcase: get headers headers INFO GET http://httpbin.org/headers INFO status_code: 200 , response_time ( ms ) : 477 .32 ms, response_length: 157 bytes . ---------------------------------------------------------------------- Ran 1 test in 0 .478s OK \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09 \u00b6 \u5f15\u7528\u63a5\u53e3\u5b9a\u4e49 \u00b6 \u6709\u4e86\u63a5\u53e3\u7684\u5b9a\u4e49\u63cf\u8ff0\u540e\uff0c\u6211\u4eec\u7f16\u5199\u6d4b\u8bd5\u573a\u666f\u65f6\u5c31\u53ef\u4ee5\u76f4\u63a5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\u4e86\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 api \u5b57\u6bb5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94 API \u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 - config : name : \"setup and reset all.\" variables : user_agent : 'iOS/10.3' device_sn : \"TESTCASE_SETUP_XXX\" os_platform : 'ios' app_version : '2.8.6' base_url : \"http://127.0.0.1:5000\" verify : False output : - session_token - test : name : get token (setup) api : api/get_token.yml variables : user_agent : 'iOS/10.3' device_sn : $device_sn os_platform : 'ios' app_version : '2.8.6' extract : - session_token : content.token validate : - eq : [ \"status_code\" , 200 ] - len_eq : [ \"content.token\" , 16 ] - test : name : reset all users api : api/reset_all.yml variables : token : $session_token \u82e5\u9700\u8981\u63a7\u5236\u6216\u6539\u53d8\u63a5\u53e3\u5b9a\u4e49\u4e2d\u7684\u53c2\u6570\u503c\uff0c\u53ef\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u6307\u5b9a variables \u53c2\u6570\uff0c\u8986\u76d6 API \u4e2d\u7684 variables \u5b9e\u73b0\u3002 \u540c\u6837\u5730\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49 validate \u540e\uff0c\u4e5f\u4f1a\u4e0e API \u4e2d\u7684 validate \u5408\u5e76\u8986\u76d6\u3002\u56e0\u6b64\u63a8\u8350\u7684\u505a\u6cd5\u662f\uff0c\u5728 API \u5b9a\u4e49\u4e2d\u7684 validate \u53ea\u63cf\u8ff0\u6700\u57fa\u672c\u7684\u6821\u9a8c\u9879\uff0c\u4f8b\u5982 status_code\uff0c\u5bf9\u4e8e\u4e0e\u4e1a\u52a1\u903b\u8f91\u76f8\u5173\u7684\u66f4\u591a\u6821\u9a8c\u9879\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u8fdb\u884c\u63cf\u8ff0\u3002 \u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b \u00b6 \u5728\u6d4b\u8bd5\u7528\u4f8b\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u9664\u4e86\u53ef\u4ee5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u8fd8\u53ef\u4ee5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5728\u907f\u514d\u91cd\u590d\u63cf\u8ff0\u7684\u540c\u65f6\uff0c\u89e3\u51b3\u6d4b\u8bd5\u7528\u4f8b\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u4ece\u800c\u4fdd\u8bc1\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u72ec\u7acb\u53ef\u8fd0\u884c\u7684\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 testcase \u5b57\u6bb5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 \u4f8b\u5982\uff0c\u5728\u4e0a\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\"setup and reset all.\"\uff09\u4e2d\uff0c\u5b9e\u73b0\u4e86\u5bf9\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\uff1b\u540c\u65f6\uff0c\u5728\u5f88\u591a\u5176\u5b83\u529f\u80fd\u4e2d\u90fd\u4f1a\u4f9d\u8d56\u4e8e\u83b7\u53d6 token \u7684\u529f\u80fd\uff0c\u5982\u679c\u5c06\u8be5\u529f\u80fd\u7684\u6d4b\u8bd5\u6b65\u9aa4\u811a\u672c\u62f7\u8d1d\u5230\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u90a3\u4e48\u5c31\u4f1a\u5b58\u5728\u5927\u91cf\u91cd\u590d\uff0c\u5f53\u9700\u8981\u5bf9\u8be5\u90e8\u5206\u8fdb\u884c\u4fee\u6539\u65f6\u5c31\u9700\u8981\u4fee\u6539\u6240\u6709\u5730\u65b9\uff0c\u663e\u7136\u4e0d\u4fbf\u4e8e\u7ef4\u62a4\u3002 \u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5728\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\u5982\u521b\u5efa\u7528\u6237\uff09\u4e2d\uff0c\u5f15\u7528\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08testcases/setup.yml\uff09\u4f5c\u4e3a\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4ece\u800c\u521b\u5efa\u7528\u6237\uff08\"create user and check result.\"\uff09\u8fd9\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u53d8\u5f97\u72ec\u7acb\u53ef\u8fd0\u884c\u4e86\u3002 - config : name : \"create user and check result.\" id : create_user base_url : \"http://127.0.0.1:5000\" variables : uid : 9001 device_sn : \"TESTCASE_CREATE_XXX\" output : - session_token - test : name : setup and reset all (override) for $device_sn. testcase : testcases/setup.yml output : - session_token - test : name : create user and check result. variables : token : $session_token testcase : testcases/deps/check_and_create.yml \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09 \u00b6 \u5f53\u6d4b\u8bd5\u7528\u4f8b\u6570\u91cf\u6bd4\u8f83\u591a\u4ee5\u540e\uff0c\u4e3a\u4e86\u65b9\u4fbf\u7ba1\u7406\u548c\u5b9e\u73b0\u6279\u91cf\u8fd0\u884c\uff0c\u901a\u5e38\u9700\u8981\u4f7f\u7528\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6765\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u7ec4\u7ec7\u3002 \u5728\u524d\u6587\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\u4e2d\u4e5f\u5f3a\u8c03\u4e86\uff0c\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406\u3002 \u56e0\u4e3a\u662f \u65e0\u5e8f \u96c6\u5408\uff0c\u56e0\u6b64\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u4f1a\u4e0e\u6d4b\u8bd5\u7528\u4f8b\u6709\u4e9b\u4e0d\u540c\uff0c\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6587\u4ef6\u4e2d\uff0c\u7b2c\u4e00\u5c42\u7ea7\u5b58\u5728\u4e24\u7c7b\u5b57\u6bb5\uff1a config: \u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u603b\u4f53\u914d\u7f6e\u53c2\u6570 testcases: \u503c\u4e3a\u5b57\u5178\u7ed3\u6784\uff08\u65e0\u5e8f\uff09\uff0ckey \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0cvalue \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5185\u5bb9\uff1b\u5728\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u65f6\u4e5f\u53ef\u4ee5\u6307\u5b9a variables\uff0c\u5b9e\u73b0\u5bf9\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u4e2d variables \u7684\u8986\u76d6\u3002 \u975e\u53c2\u6570\u5316\u573a\u666f \u00b6 config : name : create users with uid variables : device_sn : ${gen_random_string(15)} var_a : ${gen_random_string(5)} var_b : $var_a base_url : \"http://127.0.0.1:5000\" testcases : create user 1000 and check result. : testcase : testcases/create_user.yml variables : uid : 1000 var_c : ${gen_random_string(5)} var_d : $var_c create user 1001 and check result. : testcase : testcases/create_user.yml variables : uid : 1001 var_c : ${gen_random_string(5)} var_d : $var_c \u53c2\u6570\u5316\u573a\u666f\uff08parameters\uff09 \u00b6 \u5bf9\u4e8e\u53c2\u6570\u5316\u573a\u666f\uff0c\u53ef\u901a\u8fc7 parameters \u5b9e\u73b0\uff0c\u63cf\u8ff0\u5f62\u5f0f\u5982\u4e0b\u6240\u793a\u3002 config : name : create users with parameters variables : device_sn : ${gen_random_string(15)} base_url : \"http://127.0.0.1:5000\" testcases : create user $uid and check result for $device_sn. : testcase : testcases/create_user.yml variables : uid : 1000 device_sn : TESTSUITE_XXX parameters : uid : [ 101 , 102 , 103 ] device_sn : [ TESTSUITE_X1 , TESTSUITE_X2 ] \u53c2\u6570\u5316\u540e\uff0cparameters \u4e2d\u7684\u53d8\u91cf\u5c06\u91c7\u7528\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\u5f62\u6210\u53c2\u6570\u5217\u8868\uff0c\u4f9d\u6b21\u8986\u76d6 variables \u4e2d\u7684\u53c2\u6570\uff0c\u9a71\u52a8\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u3002 \u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u7ba1\u7406 && \u811a\u624b\u67b6\u5de5\u5177 \u00b6 \u5728\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u7ec4\u7ec7\u7ba1\u7406\u65f6\uff0c\u5bf9\u4e8e\u6587\u4ef6\u7684\u5b58\u50a8\u4f4d\u7f6e\u5747\u6ca1\u6709\u8981\u6c42\u548c\u9650\u5236\uff0c\u5728\u5f15\u7528\u65f6\u53ea\u9700\u8981\u6307\u5b9a\u5bf9\u5e94\u7684\u6587\u4ef6\u8def\u5f84\u5373\u53ef\u3002\u4f46\u4ece\u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e\u7684\u89d2\u5ea6\uff0c\u6700\u597d\u662f\u6309\u7167\u63a8\u8350\u7684\u6587\u4ef6\u5939\u540d\u79f0\u8fdb\u884c\u5b58\u50a8\u7ba1\u7406\uff0c\u5e76\u53ef\u901a\u8fc7\u5b50\u76ee\u5f55\u5b9e\u73b0\u9879\u76ee\u6a21\u5757\u5206\u7c7b\u7ba1\u7406\u3002 \u63a8\u8350\u7684\u65b9\u5f0f\u6c47\u603b\u5982\u4e0b\uff1a debugtalk.py \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u5047\u8bbe\u4e3a PRJ_ROOT_DIR .env \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/.env \u63a5\u53e3\u5b9a\u4e49\uff08API\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/api/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testcases/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u6587\u4ef6\u5fc5\u987b\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testsuites/ \u76ee\u5f55\u4e0b data \u6587\u4ef6\u5939\uff1a\u5b58\u50a8\u53c2\u6570\u5316\u6587\u4ef6\uff0c\u6216\u8005\u9879\u76ee\u4f9d\u8d56\u7684\u6587\u4ef6\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/data/ reports \u6587\u4ef6\u5939\uff1a\u5b58\u50a8 \bHTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u751f\u6210\u8def\u5f84\u4e3a PRJ_ROOT_DIR/reports/ \u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a $ tree tests tests \u251c\u2500\u2500 .env \u251c\u2500\u2500 data \u2502 \u251c\u2500\u2500 app_version.csv \u2502 \u2514\u2500\u2500 account.csv \u251c\u2500\u2500 api \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 get_headers.yml \u2502 \u251c\u2500\u2500 get_token.yml \u2502 \u251c\u2500\u2500 get_user.yml \u2502 \u2514\u2500\u2500 reset_all.yml \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 testcases \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 deps \u2502 \u2502 \u2514\u2500\u2500 check_and_create.yml \u2502 \u2514\u2500\u2500 setup.yml \u2514\u2500\u2500 testsuites \u251c\u2500\u2500 create_users.yml \u2514\u2500\u2500 create_users_with_parameters.yml \u9879\u76ee\u811a\u624b\u67b6 \u540c\u65f6\uff0c\u5728 HttpRunner \u4e2d\u5b9e\u73b0\u4e86\u4e00\u4e2a\u811a\u624b\u67b6\u5de5\u5177\uff0c\u53ef\u4ee5\u5feb\u901f\u521b\u5efa\u9879\u76ee\u7684\u76ee\u5f55\u7ed3\u6784\u3002\u8be5\u60f3\u6cd5\u6765\u6e90\u4e8e Django \u7684 django-admin.py startproject project_name \u3002 \u4f7f\u7528\u65b9\u5f0f\u4e5f\u4e0e Django \u7c7b\u4f3c\uff0c\u53ea\u9700\u8981\u901a\u8fc7 --startproject \u6307\u5b9a\u65b0\u9879\u76ee\u7684\u540d\u79f0\u5373\u53ef\u3002 $ hrun --startproject demo Start to create new project: demo CWD: /Users/debugtalk/MyProjects/examples created folder: demo created folder: demo/api created folder: demo/testcases created folder: demo/testsuites created folder: demo/reports created file: demo/debugtalk.py created file: demo/.env \u76f8\u5173\u53c2\u8003 \u00b6 \u300aHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff08\u5df2\u8fc7\u671f\uff09\u300b \u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u8be6\u7ec6\u793a\u4f8b\uff1a HttpRunner/tests","title":"\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42"},{"location":"prepare/testcase-layer/#_1","text":"\u5728\u81ea\u52a8\u5316\u6d4b\u8bd5\u9886\u57df\uff0c\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u53ef\u7ef4\u62a4\u6027\u662f\u6781\u5176\u91cd\u8981\u7684\u56e0\u7d20\uff0c\u76f4\u63a5\u5173\u7cfb\u5230\u81ea\u52a8\u5316\u6d4b\u8bd5\u80fd\u5426\u6301\u7eed\u6709\u6548\u5730\u5728\u9879\u76ee\u4e2d\u5f00\u5c55\u3002 \u6982\u62ec\u6765\u8bf4\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\u7684\u6838\u5fc3\u662f\u5c06\u63a5\u53e3\u5b9a\u4e49\u3001\u6d4b\u8bd5\u6b65\u9aa4\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u573a\u666f\u8fdb\u884c\u5206\u79bb\uff0c\u5355\u72ec\u8fdb\u884c\u63cf\u8ff0\u548c\u7ef4\u62a4\uff0c\u4ece\u800c\u5c3d\u53ef\u80fd\u5730\u51cf\u5c11\u81ea\u52a8\u5316\u6d4b\u8bd5\u7528\u4f8b\u7684\u7ef4\u62a4\u6210\u672c\u3002 \u903b\u8f91\u5173\u7cfb\u56fe\u5982\u4e0b\u6240\u793a\uff1a \u540c\u65f6\uff0c\u5f3a\u8c03\u5982\u4e0b\u51e0\u70b9\u6838\u5fc3\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u5e94\u8be5\u662f\u5b8c\u6574\u4e14\u72ec\u7acb\u7684\uff0c\u6bcf\u6761\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u662f\u90fd\u53ef\u4ee5\u72ec\u7acb\u8fd0\u884c\u7684 \u6d4b\u8bd5\u7528\u4f8b\u662f\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u7684 \u6709\u5e8f \u96c6\u5408\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\u5bf9\u5e94\u4e00\u4e2a API \u7684\u8bf7\u6c42\u63cf\u8ff0 \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406 \u5982\u679c\u5bf9\u4e8e\u4e0a\u8ff0\u7b2c\u4e09\u70b9\u611f\u89c9\u96be\u4ee5\u7406\u89e3\uff0c\u4e0d\u59a8\u770b\u4e0b\u4e0a\u56fe\u4e2d\u7684\u793a\u4f8b\uff1a testcase1 \u4f9d\u8d56\u4e8e testcase2\uff0c\u90a3\u4e48\u5c31\u53ef\u4ee5\u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep12\uff09\u4e2d\u5bf9 testcase2 \u8fdb\u884c\u5f15\u7528\uff0c\u7136\u540e testcase1 \u5c31\u662f\u5b8c\u6574\u4e14\u53ef\u72ec\u7acb\u8fd0\u884c\u7684\uff1b \u5728 testsuite \u4e2d\uff0ctestcase1 \u4e0e testcase2 \u76f8\u4e92\u72ec\u7acb\uff0c\u8fd0\u884c\u987a\u5e8f\u5c31\u4e0d\u518d\u6709\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u4e86\u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b"},{"location":"prepare/testcase-layer/#_2","text":"\u7406\u89e3\u4e86\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\uff0c\u63a5\u4e0b\u6765\u6211\u4eec\u518d\u6765\u770b\u4e0b\u5728\u5206\u5c42\u6a21\u578b\u4e0b\uff0c\u63a5\u53e3\u3001\u6d4b\u8bd5\u7528\u4f8b\u3001\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u3002","title":"\u5206\u5c42\u63cf\u8ff0\u8be6\u89e3"},{"location":"prepare/testcase-layer/#api","text":"\u4e3a\u4e86\u66f4\u597d\u5730\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u7ba1\u7406\uff0c\u63a8\u8350\u4f7f\u7528\u72ec\u7acb\u7684\u6587\u4ef6\u5bf9\u63a5\u53e3\u63cf\u8ff0\u8fdb\u884c\u5b58\u50a8\uff0c\u5373\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u63a5\u53e3\u63cf\u8ff0\u3002 \u63a5\u53e3\u5b9a\u4e49\u63cf\u8ff0\u7684\u4e3b\u8981\u5185\u5bb9\u5305\u62ec\uff1a name \u3001variables\u3001 request \u3001base_url\u3001validate \u7b49\uff0c\u5f62\u5f0f\u5982\u4e0b\uff1a name : get headers base_url : http://httpbin.org variables : expected_status_code : 200 request : url : /headers method : GET validate : - eq : [ \"status_code\" , $expected_status_code ] - eq : [ content.headers.Host , \"httpbin.org\" ] \u5176\u4e2d\uff0cname \u548c request \u90e8\u5206\u662f\u5fc5\u987b\u7684\uff0crequest \u4e2d\u7684\u63cf\u8ff0\u5f62\u5f0f\u4e0e requests.request \u5b8c\u5168\u76f8\u540c\u3002 \u53e6\u5916\uff0cAPI \u63cf\u8ff0\u9700\u8981\u5c3d\u91cf\u4fdd\u6301\u5b8c\u6574\uff0c\u505a\u5230\u53ef\u4ee5\u5355\u72ec\u8fd0\u884c\u3002\u5982\u679c\u5728\u63a5\u53e3\u63cf\u8ff0\u4e2d\u5b58\u5728\u53d8\u91cf\u5f15\u7528\u7684\u60c5\u51b5\uff0c\u53ef\u5728 variables \u4e2d\u5bf9\u53c2\u6570\u8fdb\u884c\u5b9a\u4e49\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5f88\u597d\u5730\u5b9e\u73b0\u5355\u4e2a\u63a5\u53e3\u7684\u8c03\u8bd5\u3002 $ hrun api/get_headers.yml INFO Start to run testcase: get headers headers INFO GET http://httpbin.org/headers INFO status_code: 200 , response_time ( ms ) : 477 .32 ms, response_length: 157 bytes . ---------------------------------------------------------------------- Ran 1 test in 0 .478s OK","title":"\u63a5\u53e3\u5b9a\u4e49\uff08API\uff09"},{"location":"prepare/testcase-layer/#testcase","text":"","title":"\u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09"},{"location":"prepare/testcase-layer/#_3","text":"\u6709\u4e86\u63a5\u53e3\u7684\u5b9a\u4e49\u63cf\u8ff0\u540e\uff0c\u6211\u4eec\u7f16\u5199\u6d4b\u8bd5\u573a\u666f\u65f6\u5c31\u53ef\u4ee5\u76f4\u63a5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\u4e86\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 api \u5b57\u6bb5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94 API \u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 - config : name : \"setup and reset all.\" variables : user_agent : 'iOS/10.3' device_sn : \"TESTCASE_SETUP_XXX\" os_platform : 'ios' app_version : '2.8.6' base_url : \"http://127.0.0.1:5000\" verify : False output : - session_token - test : name : get token (setup) api : api/get_token.yml variables : user_agent : 'iOS/10.3' device_sn : $device_sn os_platform : 'ios' app_version : '2.8.6' extract : - session_token : content.token validate : - eq : [ \"status_code\" , 200 ] - len_eq : [ \"content.token\" , 16 ] - test : name : reset all users api : api/reset_all.yml variables : token : $session_token \u82e5\u9700\u8981\u63a7\u5236\u6216\u6539\u53d8\u63a5\u53e3\u5b9a\u4e49\u4e2d\u7684\u53c2\u6570\u503c\uff0c\u53ef\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u6307\u5b9a variables \u53c2\u6570\uff0c\u8986\u76d6 API \u4e2d\u7684 variables \u5b9e\u73b0\u3002 \u540c\u6837\u5730\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49 validate \u540e\uff0c\u4e5f\u4f1a\u4e0e API \u4e2d\u7684 validate \u5408\u5e76\u8986\u76d6\u3002\u56e0\u6b64\u63a8\u8350\u7684\u505a\u6cd5\u662f\uff0c\u5728 API \u5b9a\u4e49\u4e2d\u7684 validate \u53ea\u63cf\u8ff0\u6700\u57fa\u672c\u7684\u6821\u9a8c\u9879\uff0c\u4f8b\u5982 status_code\uff0c\u5bf9\u4e8e\u4e0e\u4e1a\u52a1\u903b\u8f91\u76f8\u5173\u7684\u66f4\u591a\u6821\u9a8c\u9879\uff0c\u5728\u6d4b\u8bd5\u6b65\u9aa4\u7684 validate \u4e2d\u8fdb\u884c\u63cf\u8ff0\u3002","title":"\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49"},{"location":"prepare/testcase-layer/#_4","text":"\u5728\u6d4b\u8bd5\u7528\u4f8b\u7684\u6d4b\u8bd5\u6b65\u9aa4\u4e2d\uff0c\u9664\u4e86\u53ef\u4ee5\u5f15\u7528\u63a5\u53e3\u5b9a\u4e49\uff0c\u8fd8\u53ef\u4ee5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ef\u4ee5\u5728\u907f\u514d\u91cd\u590d\u63cf\u8ff0\u7684\u540c\u65f6\uff0c\u89e3\u51b3\u6d4b\u8bd5\u7528\u4f8b\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u4ece\u800c\u4fdd\u8bc1\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u90fd\u662f\u72ec\u7acb\u53ef\u8fd0\u884c\u7684\u3002 \u5728\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\u4e2d\uff0c\u53ef\u901a\u8fc7 testcase \u5b57\u6bb5\u5f15\u7528\u5176\u5b83\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5f15\u7528\u65b9\u5f0f\u4e3a\u5bf9\u5e94\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u7edd\u5bf9\u8def\u5f84\u6216\u76f8\u5bf9\u8def\u5f84\u5747\u53ef\u3002\u63a8\u8350\u4f7f\u7528\u76f8\u5bf9\u8def\u5f84\uff0c\u8def\u5f84\u57fa\u51c6\u4e3a\u9879\u76ee\u6839\u76ee\u5f55\uff0c\u5373 debugtalk.py \u6240\u5728\u7684\u76ee\u5f55\u8def\u5f84\u3002 \u4f8b\u5982\uff0c\u5728\u4e0a\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\"setup and reset all.\"\uff09\u4e2d\uff0c\u5b9e\u73b0\u4e86\u5bf9\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\uff1b\u540c\u65f6\uff0c\u5728\u5f88\u591a\u5176\u5b83\u529f\u80fd\u4e2d\u90fd\u4f1a\u4f9d\u8d56\u4e8e\u83b7\u53d6 token \u7684\u529f\u80fd\uff0c\u5982\u679c\u5c06\u8be5\u529f\u80fd\u7684\u6d4b\u8bd5\u6b65\u9aa4\u811a\u672c\u62f7\u8d1d\u5230\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e2d\uff0c\u90a3\u4e48\u5c31\u4f1a\u5b58\u5728\u5927\u91cf\u91cd\u590d\uff0c\u5f53\u9700\u8981\u5bf9\u8be5\u90e8\u5206\u8fdb\u884c\u4fee\u6539\u65f6\u5c31\u9700\u8981\u4fee\u6539\u6240\u6709\u5730\u65b9\uff0c\u663e\u7136\u4e0d\u4fbf\u4e8e\u7ef4\u62a4\u3002 \u6bd4\u8f83\u597d\u7684\u505a\u6cd5\u662f\uff0c\u5728\u5176\u5b83\u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08\u5982\u521b\u5efa\u7528\u6237\uff09\u4e2d\uff0c\u5f15\u7528\u83b7\u53d6 token \u529f\u80fd\u7684\u6d4b\u8bd5\u7528\u4f8b\uff08testcases/setup.yml\uff09\u4f5c\u4e3a\u4e00\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff0c\u4ece\u800c\u521b\u5efa\u7528\u6237\uff08\"create user and check result.\"\uff09\u8fd9\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u53d8\u5f97\u72ec\u7acb\u53ef\u8fd0\u884c\u4e86\u3002 - config : name : \"create user and check result.\" id : create_user base_url : \"http://127.0.0.1:5000\" variables : uid : 9001 device_sn : \"TESTCASE_CREATE_XXX\" output : - session_token - test : name : setup and reset all (override) for $device_sn. testcase : testcases/setup.yml output : - session_token - test : name : create user and check result. variables : token : $session_token testcase : testcases/deps/check_and_create.yml","title":"\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b"},{"location":"prepare/testcase-layer/#testsuite","text":"\u5f53\u6d4b\u8bd5\u7528\u4f8b\u6570\u91cf\u6bd4\u8f83\u591a\u4ee5\u540e\uff0c\u4e3a\u4e86\u65b9\u4fbf\u7ba1\u7406\u548c\u5b9e\u73b0\u6279\u91cf\u8fd0\u884c\uff0c\u901a\u5e38\u9700\u8981\u4f7f\u7528\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6765\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u8fdb\u884c\u7ec4\u7ec7\u3002 \u5728\u524d\u6587\u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u6a21\u578b\u4e2d\u4e5f\u5f3a\u8c03\u4e86\uff0c\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u662f\u6d4b\u8bd5\u7528\u4f8b\u7684 \u65e0\u5e8f \u96c6\u5408\uff0c\u96c6\u5408\u4e2d\u7684\u6d4b\u8bd5\u7528\u4f8b\u5e94\u8be5\u90fd\u662f\u76f8\u4e92\u72ec\u7acb\uff0c\u4e0d\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\u7684\uff1b\u5982\u679c\u786e\u5b9e\u5b58\u5728\u5148\u540e\u4f9d\u8d56\u5173\u7cfb\uff0c\u90a3\u5c31\u9700\u8981\u5728\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b8c\u6210\u4f9d\u8d56\u7684\u5904\u7406\u3002 \u56e0\u4e3a\u662f \u65e0\u5e8f \u96c6\u5408\uff0c\u56e0\u6b64\u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u63cf\u8ff0\u5f62\u5f0f\u4f1a\u4e0e\u6d4b\u8bd5\u7528\u4f8b\u6709\u4e9b\u4e0d\u540c\uff0c\u5728\u6bcf\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u6587\u4ef6\u4e2d\uff0c\u7b2c\u4e00\u5c42\u7ea7\u5b58\u5728\u4e24\u7c7b\u5b57\u6bb5\uff1a config: \u6d4b\u8bd5\u7528\u4f8b\u96c6\u7684\u603b\u4f53\u914d\u7f6e\u53c2\u6570 testcases: \u503c\u4e3a\u5b57\u5178\u7ed3\u6784\uff08\u65e0\u5e8f\uff09\uff0ckey \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0cvalue \u4e3a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5185\u5bb9\uff1b\u5728\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u65f6\u4e5f\u53ef\u4ee5\u6307\u5b9a variables\uff0c\u5b9e\u73b0\u5bf9\u5f15\u7528\u6d4b\u8bd5\u7528\u4f8b\u4e2d variables \u7684\u8986\u76d6\u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09"},{"location":"prepare/testcase-layer/#_5","text":"config : name : create users with uid variables : device_sn : ${gen_random_string(15)} var_a : ${gen_random_string(5)} var_b : $var_a base_url : \"http://127.0.0.1:5000\" testcases : create user 1000 and check result. : testcase : testcases/create_user.yml variables : uid : 1000 var_c : ${gen_random_string(5)} var_d : $var_c create user 1001 and check result. : testcase : testcases/create_user.yml variables : uid : 1001 var_c : ${gen_random_string(5)} var_d : $var_c","title":"\u975e\u53c2\u6570\u5316\u573a\u666f"},{"location":"prepare/testcase-layer/#parameters","text":"\u5bf9\u4e8e\u53c2\u6570\u5316\u573a\u666f\uff0c\u53ef\u901a\u8fc7 parameters \u5b9e\u73b0\uff0c\u63cf\u8ff0\u5f62\u5f0f\u5982\u4e0b\u6240\u793a\u3002 config : name : create users with parameters variables : device_sn : ${gen_random_string(15)} base_url : \"http://127.0.0.1:5000\" testcases : create user $uid and check result for $device_sn. : testcase : testcases/create_user.yml variables : uid : 1000 device_sn : TESTSUITE_XXX parameters : uid : [ 101 , 102 , 103 ] device_sn : [ TESTSUITE_X1 , TESTSUITE_X2 ] \u53c2\u6570\u5316\u540e\uff0cparameters \u4e2d\u7684\u53d8\u91cf\u5c06\u91c7\u7528\u7b1b\u5361\u5c14\u79ef\u7ec4\u5408\u5f62\u6210\u53c2\u6570\u5217\u8868\uff0c\u4f9d\u6b21\u8986\u76d6 variables \u4e2d\u7684\u53c2\u6570\uff0c\u9a71\u52a8\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u3002","title":"\u53c2\u6570\u5316\u573a\u666f\uff08parameters\uff09"},{"location":"prepare/testcase-layer/#_6","text":"\u5728\u5bf9\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u7ec4\u7ec7\u7ba1\u7406\u65f6\uff0c\u5bf9\u4e8e\u6587\u4ef6\u7684\u5b58\u50a8\u4f4d\u7f6e\u5747\u6ca1\u6709\u8981\u6c42\u548c\u9650\u5236\uff0c\u5728\u5f15\u7528\u65f6\u53ea\u9700\u8981\u6307\u5b9a\u5bf9\u5e94\u7684\u6587\u4ef6\u8def\u5f84\u5373\u53ef\u3002\u4f46\u4ece\u7ea6\u5b9a\u5927\u4e8e\u914d\u7f6e\u7684\u89d2\u5ea6\uff0c\u6700\u597d\u662f\u6309\u7167\u63a8\u8350\u7684\u6587\u4ef6\u5939\u540d\u79f0\u8fdb\u884c\u5b58\u50a8\u7ba1\u7406\uff0c\u5e76\u53ef\u901a\u8fc7\u5b50\u76ee\u5f55\u5b9e\u73b0\u9879\u76ee\u6a21\u5757\u5206\u7c7b\u7ba1\u7406\u3002 \u63a8\u8350\u7684\u65b9\u5f0f\u6c47\u603b\u5982\u4e0b\uff1a debugtalk.py \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u5047\u8bbe\u4e3a PRJ_ROOT_DIR .env \u653e\u7f6e\u5728\u9879\u76ee\u6839\u76ee\u5f55\u4e0b\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/.env \u63a5\u53e3\u5b9a\u4e49\uff08API\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/api/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testcases/ \u76ee\u5f55\u4e0b \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\u6587\u4ef6\u5fc5\u987b\u653e\u7f6e\u5728 PRJ_ROOT_DIR/testsuites/ \u76ee\u5f55\u4e0b data \u6587\u4ef6\u5939\uff1a\u5b58\u50a8\u53c2\u6570\u5316\u6587\u4ef6\uff0c\u6216\u8005\u9879\u76ee\u4f9d\u8d56\u7684\u6587\u4ef6\uff0c\u8def\u5f84\u4e3a PRJ_ROOT_DIR/data/ reports \u6587\u4ef6\u5939\uff1a\u5b58\u50a8 \bHTML \u6d4b\u8bd5\u62a5\u544a\uff0c\u751f\u6210\u8def\u5f84\u4e3a PRJ_ROOT_DIR/reports/ \u76ee\u5f55\u7ed3\u6784\u5982\u4e0b\u6240\u793a\uff1a $ tree tests tests \u251c\u2500\u2500 .env \u251c\u2500\u2500 data \u2502 \u251c\u2500\u2500 app_version.csv \u2502 \u2514\u2500\u2500 account.csv \u251c\u2500\u2500 api \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 get_headers.yml \u2502 \u251c\u2500\u2500 get_token.yml \u2502 \u251c\u2500\u2500 get_user.yml \u2502 \u2514\u2500\u2500 reset_all.yml \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 testcases \u2502 \u251c\u2500\u2500 create_user.yml \u2502 \u251c\u2500\u2500 deps \u2502 \u2502 \u2514\u2500\u2500 check_and_create.yml \u2502 \u2514\u2500\u2500 setup.yml \u2514\u2500\u2500 testsuites \u251c\u2500\u2500 create_users.yml \u2514\u2500\u2500 create_users_with_parameters.yml \u9879\u76ee\u811a\u624b\u67b6 \u540c\u65f6\uff0c\u5728 HttpRunner \u4e2d\u5b9e\u73b0\u4e86\u4e00\u4e2a\u811a\u624b\u67b6\u5de5\u5177\uff0c\u53ef\u4ee5\u5feb\u901f\u521b\u5efa\u9879\u76ee\u7684\u76ee\u5f55\u7ed3\u6784\u3002\u8be5\u60f3\u6cd5\u6765\u6e90\u4e8e Django \u7684 django-admin.py startproject project_name \u3002 \u4f7f\u7528\u65b9\u5f0f\u4e5f\u4e0e Django \u7c7b\u4f3c\uff0c\u53ea\u9700\u8981\u901a\u8fc7 --startproject \u6307\u5b9a\u65b0\u9879\u76ee\u7684\u540d\u79f0\u5373\u53ef\u3002 $ hrun --startproject demo Start to create new project: demo CWD: /Users/debugtalk/MyProjects/examples created folder: demo created folder: demo/api created folder: demo/testcases created folder: demo/testsuites created folder: demo/reports created file: demo/debugtalk.py created file: demo/.env","title":"\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u7ba1\u7406 && \u811a\u624b\u67b6\u5de5\u5177"},{"location":"prepare/testcase-layer/#_7","text":"\u300aHttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff08\u5df2\u8fc7\u671f\uff09\u300b \u6d4b\u8bd5\u7528\u4f8b\u5206\u5c42\u8be6\u7ec6\u793a\u4f8b\uff1a HttpRunner/tests","title":"\u76f8\u5173\u53c2\u8003"},{"location":"prepare/testcase-structure/","text":"YAML & JSON \u00b6 HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u652f\u6301\u4e24\u79cd\u6587\u4ef6\u683c\u5f0f\uff1aYAML \u548c JSON\u3002 JSON \u548c YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u5b8c\u5168\u7b49\u4ef7\uff0c\u5305\u542b\u7684\u4fe1\u606f\u5185\u5bb9\u4e5f\u5b8c\u5168\u76f8\u540c\u3002 \u5bf9\u4e8e\u65b0\u624b\u6765\u8bf4\uff0c\u63a8\u8350\u4f7f\u7528 JSON \u683c\u5f0f\uff0c\u867d\u7136\u63cf\u8ff0\u5f62\u5f0f\u4e0a\u7a0d\u663e\u7d2f\u8d58\uff0c\u4f46\u662f\u4e0d\u5bb9\u6613\u51fa\u9519\uff08\u5927\u591a\u7f16\u8f91\u5668\u90fd\u5177\u6709 JSON \u683c\u5f0f\u7684\u68c0\u6d4b\u529f\u80fd\uff09\uff1b\u540c\u65f6\uff0cHttpRunner \u4e5f\u5185\u7f6e\u4e86 JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b\u548c\u6837\u5f0f\u7f8e\u5316\u529f\u80fd\uff0c\u8be6\u60c5\u53ef\u67e5\u770b \u300aValidate & Prettify\u300b \u3002 \u5bf9\u4e8e\u719f\u6089 YAML \u683c\u5f0f\u7684\u4eba\u6765\u8bf4\uff0c\u7f16\u5199\u7ef4\u62a4 YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4f1a\u66f4\u7b80\u6d01\uff0c\u4f46\u524d\u63d0\u662f\u8981\u4fdd\u8bc1 YAML \u683c\u5f0f\u6ca1\u6709\u8bed\u6cd5\u9519\u8bef\u3002 \u5bf9\u4e8e\u4e24\u79cd\u683c\u5f0f\u7684\u5c55\u793a\u5dee\u5f02\uff0c\u53ef\u4ee5\u5bf9\u6bd4\u67e5\u770b demo-quickstart-6.json \u548c demo-quickstart-6.yml \u83b7\u53d6\u521d\u6b65\u7684\u5370\u8c61\u3002 \u540e\u9762\u4e3a\u4e86\u66f4\u6e05\u6670\u7684\u63cf\u8ff0\uff0c\u7edf\u4e00\u91c7\u7528 JSON \u683c\u5f0f\u4f5c\u4e3a\u793a\u4f8b\u3002 \u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784 \u00b6 \u5728 HttpRunner \u4e2d\uff0c\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u4e3b\u8981\u57fa\u4e8e\u4e09\u4e2a\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a\u6587\u4ef6\u5939\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08 YAML/JSON \uff09\u6587\u4ef6 \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a YAML/JSON \u6587\u4ef6\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff1a\u5bf9\u5e94 YAML/JSON \u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a test \uff0c\b\u63cf\u8ff0\u5355\u6b21\u63a5\u53e3\u6d4b\u8bd5\u7684\u5168\u90e8\u5185\u5bb9\uff0c\u5305\u62ec\u53d1\u8d77\u63a5\u53e3\u8bf7\u6c42\u3001\u89e3\u6790\u54cd\u5e94\u7ed3\u679c\u3001\u6821\u9a8c\u7ed3\u679c\u7b49 \u5bf9\u4e8e\u5355\u4e2a YAML/JSON \u6587\u4ef6\u6765\u8bf4\uff0c\u6570\u636e\u5b58\u50a8\u7ed3\u6784\u4e3a list of dict \u7684\u5f62\u5f0f\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u4e00\u4e2a\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u3002 \u5177\u4f53\u5730\uff1a config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879 test\uff1a\u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5b58\u5728\u987a\u5e8f\u5173\u7cfb\uff0c\u8fd0\u884c\u65f6\u5c06\u4ece\u524d\u5f80\u540e\u4f9d\u6b21\u8fd0\u884c\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u5bf9\u5e94\u7684 JSON \u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { ... } }, { \"test\" : { ... } }, { \"test\" : { ... } } ] \u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f5c\u7528\u57df \u00b6 \u5728\u6d4b\u8bd5\u7528\u4f8b\u5185\u90e8\uff0cHttpRunner \u5212\u5206\u4e86\u4e24\u5c42\u53d8\u91cf\u7a7a\u95f4\u4f5c\u7528\u57df\uff08context\uff09\u3002 config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff1b test\uff1a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f1a\u7ee7\u627f\u6216\u8986\u76d6 config \u4e2d\u5b9a\u4e49\u7684\u5185\u5bb9\uff1b \u82e5\u67d0\u53d8\u91cf\u5728 config \u4e2d\u5b9a\u4e49\u4e86\uff0c\u5728\u67d0 test \u4e2d\u6ca1\u6709\u5b9a\u4e49\uff0c\u5219\u8be5 test \u4f1a\u7ee7\u627f\u8be5\u53d8\u91cf \u82e5\u67d0\u53d8\u91cf\u5728 config \u548c\u67d0 test \u4e2d\u90fd\u5b9a\u4e49\u4e86\uff0c\u5219\u8be5 test \u4e2d\u4f7f\u7528\u81ea\u5df1\u5b9a\u4e49\u7684\u53d8\u91cf\u503c \u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u7684\u53d8\u91cf\u7a7a\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u4e92\u4e0d\u5f71\u54cd\uff1b \u5982\u9700\u5728\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\u4f20\u9012\u53c2\u6570\u503c\uff0c\u5219\u9700\u8981\u4f7f\u7528 extract \u5173\u952e\u5b57\uff0c\u5e76\u4e14\u53ea\u80fd\u4ece\u524d\u5f80\u540e\u4f20\u9012 config \u00b6 \"config\" : { \"name\" : \"testcase description\" , \"parameters\" : [ { \"user_agent\" : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ]}, { \"app_version\" : \"${P(app_version.csv)}\" }, { \"os_platform\" : \"${get_os_platform()}\" } ], \"variables\" : [ { \"user_agent\" : \"iOS/10.3\" }, { \"device_sn\" : \"${gen_random_string(15)}\" }, { \"os_platform\" : \"ios\" } ], \"request\" : { \"base_url\" : \"http://127.0.0.1:5000\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"$device_sn\" } }, \"output\" : [ \"token\" ] } Key required? format descrption name Yes string \u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6807\u9898 variables No list of dict \u5b9a\u4e49\u7684\u5168\u5c40\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b parameters No list of dict \u5168\u5c40\u53c2\u6570\uff0c\u7528\u4e8e\u5b9e\u73b0\u6570\u636e\u5316\u9a71\u52a8\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b request No dict request \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b\uff1b\u5e38\u7528\u53c2\u6570\u5305\u62ec base_url \u548c headers request Key required? format descrption base_url No string \u6d4b\u8bd5\u7528\u4f8b\u8bf7\u6c42 URL \u7684\u516c\u5171 host\uff0c\u6307\u5b9a\u8be5\u53c2\u6570\u540e\uff0ctest \u4e2d\u7684 url \u53ef\u4ee5\u53ea\u63cf\u8ff0 path \u90e8\u5206 headers No dict request \u4e2d headers \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b output No list \u6574\u4e2a\u7528\u4f8b\u8f93\u51fa\u7684\u53c2\u6570\u5217\u8868\uff0c\u53ef\u8f93\u51fa\u7684\u53c2\u6570\u5305\u62ec\u516c\u5171\u7684 variable \u548c extract \u7684\u53c2\u6570; \u5728 log-level \u4e3a debug \u6a21\u5f0f\u4e0b\uff0c\u4f1a\u5728 terminal \u4e2d\u6253\u5370\u51fa\u53c2\u6570\u5185\u5bb9 test \u00b6 \"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ], \"setup_hooks\" : [], \"teardown_hooks\" : [] } } Key required? format descrption name Yes string \u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0 request Yes dict HTTP \u8bf7\u6c42\u7684\u8be6\u7ec6\u5185\u5bb9\uff1b\u53ef\u7528\u53c2\u6570\u8be6\u89c1 python-requests \u5b98\u65b9\u6587\u6863 variables No list of dict \u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 extract No list \u4ece\u5f53\u524d HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5e76\u4fdd\u5b58\u5230\u53c2\u6570\u53d8\u91cf\u4e2d\uff08\u4f8b\u5982 token \uff09\uff0c\u540e\u7eed\u6d4b\u8bd5\u7528\u4f8b\u53ef\u901a\u8fc7 $token \u7684\u5f62\u5f0f\u8fdb\u884c\u5f15\u7528 validate No list \u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u7684\u7ed3\u679c\u6821\u9a8c\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\uff0c\u7528\u4e8e\u5b9e\u73b0\u5bf9\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u7ed3\u679c\u7684\u6821\u9a8c setup_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c teardown_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u6237\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c extract \u652f\u6301\u591a\u79cd\u63d0\u53d6\u65b9\u5f0f\uff1a \u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u7ed3\u6784\uff0c\u53ef\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 headers.Content-Type \u3001 content.success \uff1b \u54cd\u5e94\u7ed3\u679c\u4e3a text/html \u7ed3\u6784\uff0c\u53ef\u91c7\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 blog-motto\\\">(.*) \u8be6\u60c5\u53ef\u9605\u8bfb \u300aApiTestEngine\uff0c\u4e0d\u518d\u5c40\u9650\u4e8eAPI\u7684\u6d4b\u8bd5\u300b validate \u652f\u6301\u4e24\u79cd\u683c\u5f0f\uff1a {\"comparator_name\": [check_item, expect_value]} {\"check\": check_item, \"comparator\": comparator_name, \"expect\": expect_value} hooks setup_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e09\u4e2a\u53c2\u6570\uff1a method: \u8bf7\u6c42\u65b9\u6cd5\uff0ce.g. GET, POST, PUT url: \u8bf7\u6c42 URL kwargs: request \u7684\u53c2\u6570\u5b57\u5178 teardown_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u53c2\u6570\uff1a resp_obj: requests.Response \u5b9e\u4f8b \u5173\u4e8e setup_hooks \u548c teardown_hooks \u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u53c2\u8003 \u300ahook \u673a\u5236\u300b \u3002","title":"\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7"},{"location":"prepare/testcase-structure/#yaml-json","text":"HttpRunner \u7684\u6d4b\u8bd5\u7528\u4f8b\u652f\u6301\u4e24\u79cd\u6587\u4ef6\u683c\u5f0f\uff1aYAML \u548c JSON\u3002 JSON \u548c YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u5b8c\u5168\u7b49\u4ef7\uff0c\u5305\u542b\u7684\u4fe1\u606f\u5185\u5bb9\u4e5f\u5b8c\u5168\u76f8\u540c\u3002 \u5bf9\u4e8e\u65b0\u624b\u6765\u8bf4\uff0c\u63a8\u8350\u4f7f\u7528 JSON \u683c\u5f0f\uff0c\u867d\u7136\u63cf\u8ff0\u5f62\u5f0f\u4e0a\u7a0d\u663e\u7d2f\u8d58\uff0c\u4f46\u662f\u4e0d\u5bb9\u6613\u51fa\u9519\uff08\u5927\u591a\u7f16\u8f91\u5668\u90fd\u5177\u6709 JSON \u683c\u5f0f\u7684\u68c0\u6d4b\u529f\u80fd\uff09\uff1b\u540c\u65f6\uff0cHttpRunner \u4e5f\u5185\u7f6e\u4e86 JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b\u548c\u6837\u5f0f\u7f8e\u5316\u529f\u80fd\uff0c\u8be6\u60c5\u53ef\u67e5\u770b \u300aValidate & Prettify\u300b \u3002 \u5bf9\u4e8e\u719f\u6089 YAML \u683c\u5f0f\u7684\u4eba\u6765\u8bf4\uff0c\u7f16\u5199\u7ef4\u62a4 YAML \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4f1a\u66f4\u7b80\u6d01\uff0c\u4f46\u524d\u63d0\u662f\u8981\u4fdd\u8bc1 YAML \u683c\u5f0f\u6ca1\u6709\u8bed\u6cd5\u9519\u8bef\u3002 \u5bf9\u4e8e\u4e24\u79cd\u683c\u5f0f\u7684\u5c55\u793a\u5dee\u5f02\uff0c\u53ef\u4ee5\u5bf9\u6bd4\u67e5\u770b demo-quickstart-6.json \u548c demo-quickstart-6.yml \u83b7\u53d6\u521d\u6b65\u7684\u5370\u8c61\u3002 \u540e\u9762\u4e3a\u4e86\u66f4\u6e05\u6670\u7684\u63cf\u8ff0\uff0c\u7edf\u4e00\u91c7\u7528 JSON \u683c\u5f0f\u4f5c\u4e3a\u793a\u4f8b\u3002","title":"YAML & JSON"},{"location":"prepare/testcase-structure/#_1","text":"\u5728 HttpRunner \u4e2d\uff0c\u6d4b\u8bd5\u7528\u4f8b\u7ec4\u7ec7\u4e3b\u8981\u57fa\u4e8e\u4e09\u4e2a\u6982\u5ff5\uff1a \u6d4b\u8bd5\u7528\u4f8b\u96c6\uff08testsuite\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a\u6587\u4ef6\u5939\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff08 YAML/JSON \uff09\u6587\u4ef6 \u6d4b\u8bd5\u7528\u4f8b\uff08testcase\uff09\uff1a\u5bf9\u5e94\u4e00\u4e2a YAML/JSON \u6587\u4ef6\uff0c\u5305\u542b\u5355\u4e2a\u6216\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff1a\u5bf9\u5e94 YAML/JSON \u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a test \uff0c\b\u63cf\u8ff0\u5355\u6b21\u63a5\u53e3\u6d4b\u8bd5\u7684\u5168\u90e8\u5185\u5bb9\uff0c\u5305\u62ec\u53d1\u8d77\u63a5\u53e3\u8bf7\u6c42\u3001\u89e3\u6790\u54cd\u5e94\u7ed3\u679c\u3001\u6821\u9a8c\u7ed3\u679c\u7b49 \u5bf9\u4e8e\u5355\u4e2a YAML/JSON \u6587\u4ef6\u6765\u8bf4\uff0c\u6570\u636e\u5b58\u50a8\u7ed3\u6784\u4e3a list of dict \u7684\u5f62\u5f0f\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u4e00\u4e2a\u5168\u5c40\u914d\u7f6e\u9879\uff08config\uff09\u548c\u82e5\u5e72\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u3002 \u5177\u4f53\u5730\uff1a config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879 test\uff1a\u5bf9\u5e94\u5355\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08teststep\uff09\uff0c\u6d4b\u8bd5\u7528\u4f8b\u5b58\u5728\u987a\u5e8f\u5173\u7cfb\uff0c\u8fd0\u884c\u65f6\u5c06\u4ece\u524d\u5f80\u540e\u4f9d\u6b21\u8fd0\u884c\u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4 \u5bf9\u5e94\u7684 JSON \u683c\u5f0f\u5982\u4e0b\u6240\u793a\uff1a [ { \"config\" : { ... } }, { \"test\" : { ... } }, { \"test\" : { ... } } ]","title":"\u6d4b\u8bd5\u7528\u4f8b\u7ed3\u6784"},{"location":"prepare/testcase-structure/#context","text":"\u5728\u6d4b\u8bd5\u7528\u4f8b\u5185\u90e8\uff0cHttpRunner \u5212\u5206\u4e86\u4e24\u5c42\u53d8\u91cf\u7a7a\u95f4\u4f5c\u7528\u57df\uff08context\uff09\u3002 config\uff1a\u4f5c\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u7684\u5168\u5c40\u914d\u7f6e\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff1b test\uff1a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f1a\u7ee7\u627f\u6216\u8986\u76d6 config \u4e2d\u5b9a\u4e49\u7684\u5185\u5bb9\uff1b \u82e5\u67d0\u53d8\u91cf\u5728 config \u4e2d\u5b9a\u4e49\u4e86\uff0c\u5728\u67d0 test \u4e2d\u6ca1\u6709\u5b9a\u4e49\uff0c\u5219\u8be5 test \u4f1a\u7ee7\u627f\u8be5\u53d8\u91cf \u82e5\u67d0\u53d8\u91cf\u5728 config \u548c\u67d0 test \u4e2d\u90fd\u5b9a\u4e49\u4e86\uff0c\u5219\u8be5 test \u4e2d\u4f7f\u7528\u81ea\u5df1\u5b9a\u4e49\u7684\u53d8\u91cf\u503c \u5404\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u7684\u53d8\u91cf\u7a7a\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u4e92\u4e0d\u5f71\u54cd\uff1b \u5982\u9700\u5728\u591a\u4e2a\u6d4b\u8bd5\u6b65\u9aa4\uff08test\uff09\u4e2d\u4f20\u9012\u53c2\u6570\u503c\uff0c\u5219\u9700\u8981\u4f7f\u7528 extract \u5173\u952e\u5b57\uff0c\u5e76\u4e14\u53ea\u80fd\u4ece\u524d\u5f80\u540e\u4f20\u9012","title":"\u53d8\u91cf\u7a7a\u95f4\uff08context\uff09\u4f5c\u7528\u57df"},{"location":"prepare/testcase-structure/#config","text":"\"config\" : { \"name\" : \"testcase description\" , \"parameters\" : [ { \"user_agent\" : [ \"iOS/10.1\" , \"iOS/10.2\" , \"iOS/10.3\" ]}, { \"app_version\" : \"${P(app_version.csv)}\" }, { \"os_platform\" : \"${get_os_platform()}\" } ], \"variables\" : [ { \"user_agent\" : \"iOS/10.3\" }, { \"device_sn\" : \"${gen_random_string(15)}\" }, { \"os_platform\" : \"ios\" } ], \"request\" : { \"base_url\" : \"http://127.0.0.1:5000\" , \"headers\" : { \"Content-Type\" : \"application/json\" , \"device_sn\" : \"$device_sn\" } }, \"output\" : [ \"token\" ] } Key required? format descrption name Yes string \u6d4b\u8bd5\u7528\u4f8b\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6807\u9898 variables No list of dict \u5b9a\u4e49\u7684\u5168\u5c40\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b parameters No list of dict \u5168\u5c40\u53c2\u6570\uff0c\u7528\u4e8e\u5b9e\u73b0\u6570\u636e\u5316\u9a71\u52a8\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b request No dict request \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b\uff1b\u5e38\u7528\u53c2\u6570\u5305\u62ec base_url \u548c headers request Key required? format descrption base_url No string \u6d4b\u8bd5\u7528\u4f8b\u8bf7\u6c42 URL \u7684\u516c\u5171 host\uff0c\u6307\u5b9a\u8be5\u53c2\u6570\u540e\uff0ctest \u4e2d\u7684 url \u53ef\u4ee5\u53ea\u63cf\u8ff0 path \u90e8\u5206 headers No dict request \u4e2d headers \u7684\u516c\u5171\u53c2\u6570\uff0c\u4f5c\u7528\u57df\u4e3a\u6574\u4e2a\u7528\u4f8b output No list \u6574\u4e2a\u7528\u4f8b\u8f93\u51fa\u7684\u53c2\u6570\u5217\u8868\uff0c\u53ef\u8f93\u51fa\u7684\u53c2\u6570\u5305\u62ec\u516c\u5171\u7684 variable \u548c extract \u7684\u53c2\u6570; \u5728 log-level \u4e3a debug \u6a21\u5f0f\u4e0b\uff0c\u4f1a\u5728 terminal \u4e2d\u6253\u5370\u51fa\u53c2\u6570\u5185\u5bb9","title":"config"},{"location":"prepare/testcase-structure/#test","text":"\"test\" : { \"name\" : \"get token with $user_agent, $os_platform, $app_version\" , \"request\" : { \"url\" : \"/api/get-token\" , \"method\" : \"POST\" , \"headers\" : { \"app_version\" : \"$app_version\" , \"os_platform\" : \"$os_platform\" , \"user_agent\" : \"$user_agent\" }, \"json\" : { \"sign\" : \"${get_sign($user_agent, $device_sn, $os_platform, $app_version)}\" }, \"extract\" : [ { \"token\" : \"content.token\" } ], \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ]}, { \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]}, { \"eq\" : [ \"content.success\" , true ]} ], \"setup_hooks\" : [], \"teardown_hooks\" : [] } } Key required? format descrption name Yes string \u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0\uff0c\u5728\u6d4b\u8bd5\u62a5\u544a\u4e2d\u5c06\u4f5c\u4e3a\u6d4b\u8bd5\u6b65\u9aa4\u7684\u540d\u79f0 request Yes dict HTTP \u8bf7\u6c42\u7684\u8be6\u7ec6\u5185\u5bb9\uff1b\u53ef\u7528\u53c2\u6570\u8be6\u89c1 python-requests \u5b98\u65b9\u6587\u6863 variables No list of dict \u6d4b\u8bd5\u6b65\u9aa4\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u6b65\u9aa4 extract No list \u4ece\u5f53\u524d HTTP \u8bf7\u6c42\u7684\u54cd\u5e94\u7ed3\u679c\u4e2d\u63d0\u53d6\u53c2\u6570\uff0c\u5e76\u4fdd\u5b58\u5230\u53c2\u6570\u53d8\u91cf\u4e2d\uff08\u4f8b\u5982 token \uff09\uff0c\u540e\u7eed\u6d4b\u8bd5\u7528\u4f8b\u53ef\u901a\u8fc7 $token \u7684\u5f62\u5f0f\u8fdb\u884c\u5f15\u7528 validate No list \u6d4b\u8bd5\u7528\u4f8b\u4e2d\u5b9a\u4e49\u7684\u7ed3\u679c\u6821\u9a8c\u9879\uff0c\u4f5c\u7528\u57df\u4e3a\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\uff0c\u7528\u4e8e\u5b9e\u73b0\u5bf9\u5f53\u524d\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u7ed3\u679c\u7684\u6821\u9a8c setup_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u524d\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u4e8e\u51c6\u5907\u5de5\u4f5c teardown_hooks No list \u5728 HTTP \u8bf7\u6c42\u53d1\u9001\u540e\u6267\u884c hook \u51fd\u6570\uff0c\u4e3b\u8981\u7528\u6237\u6d4b\u8bd5\u540e\u7684\u6e05\u7406\u5de5\u4f5c extract \u652f\u6301\u591a\u79cd\u63d0\u53d6\u65b9\u5f0f\uff1a \u54cd\u5e94\u7ed3\u679c\u4e3a JSON \u7ed3\u6784\uff0c\u53ef\u91c7\u7528 . \u8fd0\u7b97\u7b26\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 headers.Content-Type \u3001 content.success \uff1b \u54cd\u5e94\u7ed3\u679c\u4e3a text/html \u7ed3\u6784\uff0c\u53ef\u91c7\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u65b9\u5f0f\uff0c\u4f8b\u5982 blog-motto\\\">(.*) \u8be6\u60c5\u53ef\u9605\u8bfb \u300aApiTestEngine\uff0c\u4e0d\u518d\u5c40\u9650\u4e8eAPI\u7684\u6d4b\u8bd5\u300b validate \u652f\u6301\u4e24\u79cd\u683c\u5f0f\uff1a {\"comparator_name\": [check_item, expect_value]} {\"check\": check_item, \"comparator\": comparator_name, \"expect\": expect_value} hooks setup_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e09\u4e2a\u53c2\u6570\uff1a method: \u8bf7\u6c42\u65b9\u6cd5\uff0ce.g. GET, POST, PUT url: \u8bf7\u6c42 URL kwargs: request \u7684\u53c2\u6570\u5b57\u5178 teardown_hooks \u51fd\u6570\u653e\u7f6e\u4e8e debugtalk.py \u4e2d\uff0c\u5e76\u4e14\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u53c2\u6570\uff1a resp_obj: requests.Response \u5b9e\u4f8b \u5173\u4e8e setup_hooks \u548c teardown_hooks \u7684\u66f4\u591a\u5185\u5bb9\uff0c\u8bf7\u53c2\u8003 \u300ahook \u673a\u5236\u300b \u3002","title":"test"},{"location":"prepare/validate-pretty/","text":"HttpRunner \u4ece 1.3.1 \u7248\u672c\u5f00\u59cb\uff0c\u652f\u6301\u5bf9 JSON \u683c\u5f0f\u6d4b\u8bd5\u7528\u4f8b\u7684\u5185\u5bb9\u8fdb\u884c\u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b\u548c\u6837\u5f0f\u7f8e\u5316\u529f\u80fd\u3002 JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b \u00b6 \u82e5\u9700\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u7684\u5185\u5bb9\u8fdb\u884c\u6b63\u786e\u6027\u68c0\u6d4b\uff0c\u53ef\u4f7f\u7528 --validate \u53c2\u6570\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json OK \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json Start to validate JSON file: docs/data/demo-quickstart.json OK WARNING Only JSON file format can be validated, skip docs/data/demo-quickstart.yml Start to validate JSON file: docs/data/demo-quickstart-0.json OK \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u6b63\u786e\uff0c\u5219\u6253\u5370 OK\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json Expecting ',' delimiter: line 5 column 13 ( char 82 ) JSON \u683c\u5f0f\u7f8e\u5316 \u00b6 \u4e0e YAML \u683c\u5f0f\u4e0d\u540c\uff0cJSON \u683c\u5f0f\u4e0d\u5f3a\u5236\u8981\u6c42\u7f29\u8fdb\u548c\u6362\u884c\uff0c\u8fd9\u6709\u70b9\u7c7b\u4f3c\u4e8e C \u8bed\u8a00\u548c Python \u8bed\u8a00\u7684\u5dee\u5f02\u3002 \u4f8b\u5982\uff0c demo-quickstart.json \u6587\u4ef6\u4e5f\u53ef\u4ee5\u6539\u5199\u4e3a\u5982\u4e0b\u5f62\u5f0f\u3002 [{ \"config\" : { \"name\" : \"testcase description\" , \"variables\" : [], \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" }}}},{ \"test\" : { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"user_agent\" : \"iOS/10.3\" , \"os_platform\" : \"ios\" , \"app_version\" : \"2.8.6\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 200 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]}]}},{ \"test\" : { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"baNLX1zhFYP11Seb\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 201 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]}]}}] \u867d\u7136\u4e0a\u9762 JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u6267\u884c\uff0c\u4f46\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u53ef\u8bfb\u6027\u592a\u5dee\uff0c\u4e0d\u5229\u4e8e\u9605\u8bfb\u548c\u7ef4\u62a4\u3002 \u9488\u5bf9\u8be5\u9700\u6c42\uff0c\u53ef\u4f7f\u7528 --prettify \u53c2\u6570\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u6837\u5f0f\u7f8e\u5316\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json WARNING Only JSON file format can be prettified, skip: docs/data/demo-quickstart.yml Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json Start to prettify JSON file: docs/data/demo-quickstart-0.json success: docs/data/demo-quickstart-0.pretty.json \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5\u8f6c\u6362\u6210\u529f\uff0c\u5219\u6253\u5370\u7f8e\u5316\u540e\u7684\u6587\u4ef6\u8def\u5f84\uff1b\u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002","title":"Validate & Prettify"},{"location":"prepare/validate-pretty/#json","text":"\u82e5\u9700\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u7684\u5185\u5bb9\u8fdb\u884c\u6b63\u786e\u6027\u68c0\u6d4b\uff0c\u53ef\u4f7f\u7528 --validate \u53c2\u6570\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json OK \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --validate docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json Start to validate JSON file: docs/data/demo-quickstart.json OK WARNING Only JSON file format can be validated, skip docs/data/demo-quickstart.yml Start to validate JSON file: docs/data/demo-quickstart-0.json OK \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u6b63\u786e\uff0c\u5219\u6253\u5370 OK\u3002 \u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002 $ hrun --validate docs/data/demo-quickstart.json Start to validate JSON file: docs/data/demo-quickstart.json Expecting ',' delimiter: line 5 column 13 ( char 82 )","title":"JSON \u683c\u5f0f\u6b63\u786e\u6027\u68c0\u6d4b"},{"location":"prepare/validate-pretty/#json_1","text":"\u4e0e YAML \u683c\u5f0f\u4e0d\u540c\uff0cJSON \u683c\u5f0f\u4e0d\u5f3a\u5236\u8981\u6c42\u7f29\u8fdb\u548c\u6362\u884c\uff0c\u8fd9\u6709\u70b9\u7c7b\u4f3c\u4e8e C \u8bed\u8a00\u548c Python \u8bed\u8a00\u7684\u5dee\u5f02\u3002 \u4f8b\u5982\uff0c demo-quickstart.json \u6587\u4ef6\u4e5f\u53ef\u4ee5\u6539\u5199\u4e3a\u5982\u4e0b\u5f62\u5f0f\u3002 [{ \"config\" : { \"name\" : \"testcase description\" , \"variables\" : [], \"request\" : { \"base_url\" : \"\" , \"headers\" : { \"User-Agent\" : \"python-requests/2.18.4\" }}}},{ \"test\" : { \"name\" : \"/api/get-token\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/get-token\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"user_agent\" : \"iOS/10.3\" , \"os_platform\" : \"ios\" , \"app_version\" : \"2.8.6\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"sign\" : \"9c0c7e51c91ae963c833a4ccbab8d683c4a90c98\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 200 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.token\" , \"baNLX1zhFYP11Seb\" ]}]}},{ \"test\" : { \"name\" : \"/api/users/1000\" , \"request\" : { \"url\" : \"http://127.0.0.1:5000/api/users/1000\" , \"headers\" : { \"device_sn\" : \"FwgRiO7CNA50DSU\" , \"token\" : \"baNLX1zhFYP11Seb\" , \"Content-Type\" : \"application/json\" }, \"method\" : \"POST\" , \"json\" : { \"name\" : \"user1\" , \"password\" : \"123456\" }}, \"validate\" : [{ \"eq\" : [ \"status_code\" , 201 ]},{ \"eq\" : [ \"headers.Content-Type\" , \"application/json\" ]},{ \"eq\" : [ \"content.success\" , true ]},{ \"eq\" : [ \"content.msg\" , \"user created successfully.\" ]}]}}] \u867d\u7136\u4e0a\u9762 JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u80fd\u6b63\u5e38\u6267\u884c\uff0c\u4f46\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u53ef\u8bfb\u6027\u592a\u5dee\uff0c\u4e0d\u5229\u4e8e\u9605\u8bfb\u548c\u7ef4\u62a4\u3002 \u9488\u5bf9\u8be5\u9700\u6c42\uff0c\u53ef\u4f7f\u7528 --prettify \u53c2\u6570\u5bf9 JSON \u683c\u5f0f\u7528\u4f8b\u6587\u4ef6\u8fdb\u884c\u6837\u5f0f\u7f8e\u5316\u3002 \u53ef\u6307\u5b9a\u5355\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json \u4e5f\u53ef\u6307\u5b9a\u591a\u4e2a JSON \u7528\u4f8b\u6587\u4ef6\u8def\u5f84\u3002 $ hrun --prettify docs/data/demo-quickstart.json docs/data/demo-quickstart.yml docs/data/demo-quickstart-0.json WARNING Only JSON file format can be prettified, skip: docs/data/demo-quickstart.yml Start to prettify JSON file: docs/data/demo-quickstart.json success: docs/data/demo-quickstart.pretty.json Start to prettify JSON file: docs/data/demo-quickstart-0.json success: docs/data/demo-quickstart-0.pretty.json \u5982\u4e0a\u6240\u793a\uff0c\u5f53\u4f20\u5165\u7684\u6587\u4ef6\u540e\u7f00\u4e0d\u662f .json \uff0cHttpRunner \u4f1a\u6253\u5370 WARNING \u4fe1\u606f\uff0c\u5e76\u8df3\u8fc7\u68c0\u6d4b\u3002 \u82e5\u8f6c\u6362\u6210\u529f\uff0c\u5219\u6253\u5370\u7f8e\u5316\u540e\u7684\u6587\u4ef6\u8def\u5f84\uff1b\u82e5 JSON \u6587\u4ef6\u683c\u5f0f\u5b58\u5728\u5f02\u5e38\uff0c\u5219\u6253\u5370\u8be6\u7ec6\u7684\u62a5\u9519\u4fe1\u606f\uff0c\u7cbe\u786e\u5230\u9519\u8bef\u5728\u6587\u4ef6\u4e2d\u51fa\u73b0\u7684\u884c\u548c\u5217\u3002","title":"JSON \u683c\u5f0f\u7f8e\u5316"},{"location":"run-tests/cli/","text":"HttpRunner \u5728\u547d\u4ee4\u884c\u4e2d\u542f\u52a8\u6d4b\u8bd5\u65f6\uff0c\u901a\u8fc7\u6307\u5b9a\u53c2\u6570\uff0c\u53ef\u5b9e\u73b0\u4e30\u5bcc\u7684\u6d4b\u8bd5\u7279\u6027\u63a7\u5236\u3002 $ hrun -h usage: hrun [-h] [-V] [--log-level LOG_LEVEL] [--log-file LOG_FILE] [--dot-env-path DOT_ENV_PATH] [--report-template REPORT_TEMPLATE] [--report-dir REPORT_DIR] [--failfast] [--save-tests] [--startproject STARTPROJECT] [--validate [VALIDATE [VALIDATE ...]]] [--prettify [PRETTIFY [PRETTIFY ...]]] [testcase_paths [testcase_paths ...]] One-stop solution for HTTP(S) testing. positional arguments: testcase_paths testcase file path optional arguments: -h, --help show this help message and exit -V, --version show version --log-level LOG_LEVEL Specify logging level, default is INFO. --log-file LOG_FILE Write logs to specified file path. --dot-env-path DOT_ENV_PATH Specify .env file path, which is useful for keeping sensitive data. --report-template REPORT_TEMPLATE specify report template path. --report-dir REPORT_DIR specify report save directory. --failfast Stop the test run on the first error or failure. --save-tests Save loaded tests and parsed tests to JSON file. --startproject STARTPROJECT Specify new project name. --validate [VALIDATE [VALIDATE ...]] Validate JSON testcase format. --prettify [PRETTIFY [PRETTIFY ...]] Prettify JSON testcase format. \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84 \u00b6 \u4f7f\u7528 HttpRunner \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84\u65f6\uff0c\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u3002 \u4f7f\u7528 hrun \u547d\u4ee4\u5916\u52a0\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u8fd0\u884c\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun filepath/testcase.yml \u5c06\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u653e\u7f6e\u5230\u6587\u4ef6\u5939\u4e2d\uff0c\u6307\u5b9a\u6587\u4ef6\u5939\u8def\u5f84\u53ef\u5c06\u6587\u4ef6\u5939\u4e0b\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\u4f5c\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u8fdb\u884c\u8fd0\u884c\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun testcases_folder_path failfast \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u4f1a\u8fd0\u884c\u6307\u5b9a\u7528\u4f8b\u96c6\u4e2d\u7684\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u7edf\u8ba1\u6d4b\u8bd5\u7ed3\u679c\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u4f9d\u8d56\u4e8e\u6267\u884c\u987a\u5e8f\u7684\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u9700\u8981\u5148\u767b\u5f55\u6210\u529f\u624d\u80fd\u6267\u884c\u540e\u7eed\u63a5\u53e3\u8bf7\u6c42\u7684\u573a\u666f\uff0c\u5f53\u524d\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\u6267\u884c\u5931\u8d25\u540e\uff0c\u540e\u7eed\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u90fd\u5fc5\u5c06\u5931\u8d25\uff0c\u56e0\u6b64\u6ca1\u6709\u7ee7\u7eed\u6267\u884c\u7684\u5fc5\u8981\u4e86\u3002 \u82e5\u5e0c\u671b\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u8fc7\u7a0b\u4e2d\uff0c\u9047\u5230\u5931\u8d25\u65f6\u4e0d\u518d\u7ee7\u7eed\u8fd0\u884c\u540e\u7eed\u7528\u4f8b\uff0c\u5219\u53ef\u901a\u8fc7\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --failfast \u5b9e\u73b0\u3002 $ hrun filepath/testcase.yml --failfast \u65e5\u5fd7\u7ea7\u522b \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u8fd0\u884c\u65f6\u7684\u65e5\u5fd7\u7ea7\u522b\u4e3a INFO \uff0c\u53ea\u4f1a\u5305\u542b\u6700\u57fa\u672c\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u7528\u4f8b\u540d\u79f0\u3001\u8bf7\u6c42\u7684URL\u548cMethod\u3001\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u3001\u8017\u65f6\u548c\u5185\u5bb9\u5927\u5c0f\u3002 $ hrun docs/data/demo-quickstart-6.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.08 ms, response_length: 46 bytes . /api/users/1548560655759 INFO POST http://127.0.0.1:5000/api/users/1548560655759 INFO status_code: 201, response_time(ms): 2.89 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560655.html \u82e5\u9700\u8981\u67e5\u770b\u5230\u66f4\u8be6\u5c3d\u7684\u4fe1\u606f\uff0c\u4f8b\u5982\u8bf7\u6c42\u7684\u53c2\u6570\u548c\u54cd\u5e94\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u53ef\u4ee5\u5c06\u65e5\u5fd7\u7ea7\u522b\u8bbe\u7f6e\u4e3a DEBUG \uff0c\u5373\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --log-level debug \u3002 $ hrun docs/data/demo-quickstart-6.json --log-level debug INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/get-token > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/get-token' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json', 'Content-Length': '52'} body : b'{\"sign\": \"2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/get-token' status_code : 200 reason : 'OK' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'token': 'o6uakmubLrCbpRRS'} INFO status_code: 200, response_time(ms): 9.28 ms, response_length: 46 bytes DEBUG start to extract from response object. DEBUG extract: content.token => o6uakmubLrCbpRRS DEBUG start to validate. DEBUG extract: status_code => 200 DEBUG validate: status_code equals 200(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass . /api/users/1548560716736 INFO POST http://127.0.0.1:5000/api/users/1548560716736 DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/users/1548560716736 > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/users/1548560716736' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json', 'Content-Length': '39'} body : b'{\"name\": \"user1\", \"password\": \"123456\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/users/1548560716736' status_code : 201 reason : 'CREATED' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '54', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'msg': 'user created successfully.'} INFO status_code: 201, response_time(ms): 2.77 ms, response_length: 54 bytes DEBUG start to validate. DEBUG extract: status_code => 201 DEBUG validate: status_code equals 201(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass DEBUG extract: content.msg => user created successfully. DEBUG validate: content.msg equals user created successfully.(str) ==> pass . ---------------------------------------------------------------------- Ran 2 tests in 0.022s OK DEBUG No html report template specified, use default. INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560716.html \u4fdd\u5b58\u8be6\u7ec6\u8fc7\u7a0b\u6570\u636e \u00b6 \u4e3a\u4e86\u65b9\u4fbf\u5b9a\u4f4d\u95ee\u9898\uff0c\u8fd0\u884c\u6d4b\u8bd5\u65f6\u53ef\u6307\u5b9a --save-tests \u53c2\u6570\uff0c\u5373\u53ef\u5c06\u8fd0\u884c\u8fc7\u7a0b\u7684\u4e2d\u95f4\u6570\u636e\u4fdd\u5b58\u4e3a\u65e5\u5fd7\u6587\u4ef6\u3002 $ hrun docs/data/demo-quickstart-6.json --save-tests dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.loaded.json dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.parsed.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 11.42 ms, response_length: 46 bytes . /api/users/1548560768589 INFO POST http://127.0.0.1:5000/api/users/1548560768589 INFO status_code: 201, response_time(ms): 2.8 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.028s OK dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.summary.json INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560768.html \u65e5\u5fd7\u6587\u4ef6\u5c06\u4fdd\u5b58\u5728\u9879\u76ee\u6839\u76ee\u5f55\u7684 logs \u6587\u4ef6\u5939\u4e2d\uff0c\u751f\u6210\u7684\u6587\u4ef6\u6709\u5982\u4e0b\u4e09\u4e2a\uff08XXX\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u540d\u79f0\uff09\uff1a XXX.loaded.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u52a0\u8f7d\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u52a0\u8f7d\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff08YAML/JSON\uff09\u3001debugtalk.py\u3001.env \u7b49\u6240\u6709\u9879\u76ee\u6587\u4ef6\uff0c\u4f8b\u5982 demo-quickstart-6.loaded.json XXX.parsed.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u89e3\u6790\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u89e3\u6790\u5185\u5bb9\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u5f15\u7528\uff08API/testcase\uff09\u3001\u53d8\u91cf\u8ba1\u7b97\u548c\u66ff\u6362\u3001base_url \u62fc\u63a5\u7b49\uff0c\u4f8b\u5982 demo-quickstart-6.parsed.json XXX.summary.json \uff1a\u6d4b\u8bd5\u62a5\u544a\u751f\u6210\u524d\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u4f8b\u5982 demo-quickstart-6.summary.json","title":"\u8fd0\u884c\u6d4b\u8bd5(CLI)"},{"location":"run-tests/cli/#_1","text":"\u4f7f\u7528 HttpRunner \u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84\u65f6\uff0c\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u3002 \u4f7f\u7528 hrun \u547d\u4ee4\u5916\u52a0\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u7684\u8def\u5f84\uff0c\u8fd0\u884c\u5355\u4e2a\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun filepath/testcase.yml \u5c06\u591a\u4e2a\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u653e\u7f6e\u5230\u6587\u4ef6\u5939\u4e2d\uff0c\u6307\u5b9a\u6587\u4ef6\u5939\u8def\u5f84\u53ef\u5c06\u6587\u4ef6\u5939\u4e0b\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\u4f5c\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u96c6\u8fdb\u884c\u8fd0\u884c\uff0c\u5e76\u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\uff1a $ hrun testcases_folder_path","title":"\u6307\u5b9a\u6d4b\u8bd5\u7528\u4f8b\u8def\u5f84"},{"location":"run-tests/cli/#failfast","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u4f1a\u8fd0\u884c\u6307\u5b9a\u7528\u4f8b\u96c6\u4e2d\u7684\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\uff0c\u5e76\u7edf\u8ba1\u6d4b\u8bd5\u7ed3\u679c\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u4f9d\u8d56\u4e8e\u6267\u884c\u987a\u5e8f\u7684\u6d4b\u8bd5\u7528\u4f8b\uff0c\u4f8b\u5982\u9700\u8981\u5148\u767b\u5f55\u6210\u529f\u624d\u80fd\u6267\u884c\u540e\u7eed\u63a5\u53e3\u8bf7\u6c42\u7684\u573a\u666f\uff0c\u5f53\u524d\u9762\u7684\u6d4b\u8bd5\u7528\u4f8b\u6267\u884c\u5931\u8d25\u540e\uff0c\u540e\u7eed\u7684\u6d4b\u8bd5\u7528\u4f8b\u4e5f\u90fd\u5fc5\u5c06\u5931\u8d25\uff0c\u56e0\u6b64\u6ca1\u6709\u7ee7\u7eed\u6267\u884c\u7684\u5fc5\u8981\u4e86\u3002 \u82e5\u5e0c\u671b\u6d4b\u8bd5\u7528\u4f8b\u5728\u8fd0\u884c\u8fc7\u7a0b\u4e2d\uff0c\u9047\u5230\u5931\u8d25\u65f6\u4e0d\u518d\u7ee7\u7eed\u8fd0\u884c\u540e\u7eed\u7528\u4f8b\uff0c\u5219\u53ef\u901a\u8fc7\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --failfast \u5b9e\u73b0\u3002 $ hrun filepath/testcase.yml --failfast","title":"failfast"},{"location":"run-tests/cli/#_2","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cHttpRunner \u8fd0\u884c\u65f6\u7684\u65e5\u5fd7\u7ea7\u522b\u4e3a INFO \uff0c\u53ea\u4f1a\u5305\u542b\u6700\u57fa\u672c\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u7528\u4f8b\u540d\u79f0\u3001\u8bf7\u6c42\u7684URL\u548cMethod\u3001\u54cd\u5e94\u7ed3\u679c\u7684\u72b6\u6001\u7801\u3001\u8017\u65f6\u548c\u5185\u5bb9\u5927\u5c0f\u3002 $ hrun docs/data/demo-quickstart-6.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 9.08 ms, response_length: 46 bytes . /api/users/1548560655759 INFO POST http://127.0.0.1:5000/api/users/1548560655759 INFO status_code: 201, response_time(ms): 2.89 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.019s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560655.html \u82e5\u9700\u8981\u67e5\u770b\u5230\u66f4\u8be6\u5c3d\u7684\u4fe1\u606f\uff0c\u4f8b\u5982\u8bf7\u6c42\u7684\u53c2\u6570\u548c\u54cd\u5e94\u7684\u8be6\u7ec6\u5185\u5bb9\uff0c\u53ef\u4ee5\u5c06\u65e5\u5fd7\u7ea7\u522b\u8bbe\u7f6e\u4e3a DEBUG \uff0c\u5373\u5728\u547d\u4ee4\u4e2d\u6dfb\u52a0 --log-level debug \u3002 $ hrun docs/data/demo-quickstart-6.json --log-level debug INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/get-token > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json'}, 'json': {'sign': '2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/get-token' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'os_platform': 'ios', 'app_version': '2.8.6', 'Content-Type': 'application/json', 'Content-Length': '52'} body : b'{\"sign\": \"2e7c3b5d560a1c8a859edcb9c8b0d3f8349abeff\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/get-token' status_code : 200 reason : 'OK' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '46', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'token': 'o6uakmubLrCbpRRS'} INFO status_code: 200, response_time(ms): 9.28 ms, response_length: 46 bytes DEBUG start to extract from response object. DEBUG extract: content.token => o6uakmubLrCbpRRS DEBUG start to validate. DEBUG extract: status_code => 200 DEBUG validate: status_code equals 200(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass . /api/users/1548560716736 INFO POST http://127.0.0.1:5000/api/users/1548560716736 DEBUG request kwargs(raw): {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True} DEBUG processed request: > POST http://127.0.0.1:5000/api/users/1548560716736 > kwargs: {'headers': {'User-Agent': 'python-requests/2.18.4', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json'}, 'json': {'name': 'user1', 'password': '123456'}, 'verify': True, 'timeout': 120} DEBUG ================== request details ================== url : 'http://127.0.0.1:5000/api/users/1548560716736' method : 'POST' headers : {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'device_sn': 'W5ACRDytKRQJPhC', 'token': 'o6uakmubLrCbpRRS', 'Content-Type': 'application/json', 'Content-Length': '39'} body : b'{\"name\": \"user1\", \"password\": \"123456\"}' DEBUG ================== response details ================== ok : True url : 'http://127.0.0.1:5000/api/users/1548560716736' status_code : 201 reason : 'CREATED' cookies : {} encoding : None headers : {'Content-Type': 'application/json', 'Content-Length': '54', 'Server': 'Werkzeug/0.14.1 Python/3.6.5+', 'Date': 'Sun, 27 Jan 2019 03:45:16 GMT'} content_type : 'application/json' json : {'success': True, 'msg': 'user created successfully.'} INFO status_code: 201, response_time(ms): 2.77 ms, response_length: 54 bytes DEBUG start to validate. DEBUG extract: status_code => 201 DEBUG validate: status_code equals 201(int) ==> pass DEBUG extract: headers.Content-Type => application/json DEBUG validate: headers.Content-Type equals application/json(str) ==> pass DEBUG extract: content.success => True DEBUG validate: content.success equals True(bool) ==> pass DEBUG extract: content.msg => user created successfully. DEBUG validate: content.msg equals user created successfully.(str) ==> pass . ---------------------------------------------------------------------- Ran 2 tests in 0.022s OK DEBUG No html report template specified, use default. INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560716.html","title":"\u65e5\u5fd7\u7ea7\u522b"},{"location":"run-tests/cli/#_3","text":"\u4e3a\u4e86\u65b9\u4fbf\u5b9a\u4f4d\u95ee\u9898\uff0c\u8fd0\u884c\u6d4b\u8bd5\u65f6\u53ef\u6307\u5b9a --save-tests \u53c2\u6570\uff0c\u5373\u53ef\u5c06\u8fd0\u884c\u8fc7\u7a0b\u7684\u4e2d\u95f4\u6570\u636e\u4fdd\u5b58\u4e3a\u65e5\u5fd7\u6587\u4ef6\u3002 $ hrun docs/data/demo-quickstart-6.json --save-tests dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.loaded.json dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.parsed.json INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200, response_time(ms): 11.42 ms, response_length: 46 bytes . /api/users/1548560768589 INFO POST http://127.0.0.1:5000/api/users/1548560768589 INFO status_code: 201, response_time(ms): 2.8 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0.028s OK dump file: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/docs/data/logs/demo-quickstart-6.summary.json INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548560768.html \u65e5\u5fd7\u6587\u4ef6\u5c06\u4fdd\u5b58\u5728\u9879\u76ee\u6839\u76ee\u5f55\u7684 logs \u6587\u4ef6\u5939\u4e2d\uff0c\u751f\u6210\u7684\u6587\u4ef6\u6709\u5982\u4e0b\u4e09\u4e2a\uff08XXX\u4e3a\u6d4b\u8bd5\u7528\u4f8b\u540d\u79f0\uff09\uff1a XXX.loaded.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u52a0\u8f7d\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u52a0\u8f7d\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\uff08YAML/JSON\uff09\u3001debugtalk.py\u3001.env \u7b49\u6240\u6709\u9879\u76ee\u6587\u4ef6\uff0c\u4f8b\u5982 demo-quickstart-6.loaded.json XXX.parsed.json \uff1a\u6d4b\u8bd5\u7528\u4f8b\u89e3\u6790\u540e\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u89e3\u6790\u5185\u5bb9\u5305\u62ec\u6d4b\u8bd5\u7528\u4f8b\u5f15\u7528\uff08API/testcase\uff09\u3001\u53d8\u91cf\u8ba1\u7b97\u548c\u66ff\u6362\u3001base_url \u62fc\u63a5\u7b49\uff0c\u4f8b\u5982 demo-quickstart-6.parsed.json XXX.summary.json \uff1a\u6d4b\u8bd5\u62a5\u544a\u751f\u6210\u524d\u7684\u6570\u636e\u7ed3\u6784\u5185\u5bb9\uff0c\u4f8b\u5982 demo-quickstart-6.summary.json","title":"\u4fdd\u5b58\u8be6\u7ec6\u8fc7\u7a0b\u6570\u636e"},{"location":"run-tests/load-test/","text":"HttpRunner \u901a\u8fc7\u590d\u7528 Locust \uff0c\u53ef\u4ee5\u5728\u65e0\u9700\u5bf9 YAML/JSON \u8fdb\u884c\u4efb\u4f55\u4fee\u6539\u7684\u60c5\u51b5\u4e0b\uff0c\u76f4\u63a5\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5\u3002 \u539f\u7406\u56fe \u00b6 \u5b89\u88c5\u4f9d\u8d56\u5305 \u00b6 \u5b89\u88c5\u5b8c\u6210 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e locusts \u547d\u4ee4\uff0c\u4f46\u4e0d\u4f1a\u540c\u65f6\u5b89\u88c5 Locust\u3002 \u5728\u7cfb\u7edf\u4e2d\u672a\u5b89\u88c5 Locust \u7684\u60c5\u51b5\u4e0b\uff0c\u8fd0\u884c locusts \u547d\u4ee4\u65f6\u4f1a\u51fa\u73b0\u5982\u4e0b\u63d0\u793a\u3002 $ locusts -V WARNING Locust is not installed, install first and try again. install command: pip install locustio Locust \u7684\u5b89\u88c5\u65b9\u5f0f\u5982\u4e0b\uff1a $ pip install locustio \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u6267\u884c locusts -V \u53ef\u67e5\u770b\u5230 Locust \u7684\u7248\u672c\u53f7\u3002 $ locusts -V [2017-08-26 23:45:42,246] bogon/INFO/stdout: Locust 0.8a2 [2017-08-26 23:45:42,246] bogon/INFO/stdout: \u6267\u884c locusts -h \uff0c\u53ef\u67e5\u770b\u5230\u4f7f\u7528\u5e2e\u52a9\u6587\u6863\u3002 $ locusts -h Usage: locust [options] [LocustClass [LocustClass2 ... ]] Options: -h, --help show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33 --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE Store current request stats to files in CSV format. --master Set locust to run in distributed mode with this process as master --slave Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats --no-reset-stats Do not reset statistics once hatching has been completed -l, --list Show list of possible locust classes and exit --show-task-ratio print table of the locust classes' task execution ratio --show-task-ratio-json print json data of the locust classes' task execution ratio -V, --version show program's version number and exit \u53ef\u4ee5\u770b\u51fa\uff0c loucsts \u547d\u4ee4\u4e0e locust \u547d\u4ee4\u7684\u7528\u6cd5\u57fa\u672c\u76f8\u540c\u3002 \u76f8\u6bd4\u4e8e locust \u547d\u4ee4\uff0c loucsts \u547d\u4ee4\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u4e24\u9879\u5dee\u5f02\u3002 \u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5 \u00b6 \u5728 -f \u53c2\u6570\u540e\u9762\uff0c loucsts \u547d\u4ee4\u4e0d\u4ec5\u53ef\u4ee5\u6307\u5b9a Locust \u652f\u6301\u7684 Python \u6587\u4ef6\uff0c\u540c\u65f6\u53ef\u4ee5\u76f4\u63a5\u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002\u5728\u5177\u4f53\u5b9e\u73b0\u4e0a\uff0c\u5f53 -f \u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u65f6\uff0c\u4f1a\u5148\u5c06\u5176\u8f6c\u6362\u4e3a Python \u683c\u5f0f\u7684 locustfile\uff0c\u7136\u540e\u518d\u5c06 locustfile.py \u4f20\u7ed9 locust \u547d\u4ee4\u3002 $ locusts -f examples/first-testcase.yml [ 2017 -08-18 17 :20:43,915 ] Leos-MacBook-Air.local/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-18 17 :20:43,918 ] Leos-MacBook-Air.local/INFO/locust.main: Starting Locust 0 .8a2 \u6267\u884c\u4e0a\u8ff0\u547d\u4ee4\u540e\uff0c\u5373\u5b8c\u6210\u4e86 Locust \u670d\u52a1\u7684\u542f\u52a8\uff0c\u540e\u7eed\u5c31\u53ef\u4ee5\u5728 Locust \u7684 Web \u7ba1\u7406\u754c\u9762\u4e2d\u8fdb\u884c\u64cd\u4f5c\u4e86\uff0c\u4f7f\u7528\u65b9\u5f0f\u4e0e Locust \u5b8c\u5168\u76f8\u540c\u3002 \u591a\u8fdb\u7a0b\u8fd0\u884c\u6a21\u5f0f \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728 Locust \u4e2d\u5982\u9700\u4f7f\u7528 master-slave \u6a21\u5f0f\u542f\u52a8\u591a\u4e2a\u8fdb\u7a0b\uff08\u4f7f\u7528\u591a\u6838\u5904\u7406\u5668\u7684\u80fd\u529b\uff09\uff0c\u53ea\u80fd\u5148\u542f\u52a8 master\uff0c\u7136\u540e\u518d\u9010\u4e00\u542f\u52a8\u82e5\u5e72\u4e2a slave\u3002 $ locust -f locustfile.py --master $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & \u5728 HttpRunner \u4e2d\uff0c\u65b0\u589e\u5b9e\u73b0 --processes \u53c2\u6570\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u542f\u52a8 1 \u4e2a master \u548c\u591a\u4e2a salve\u3002\u82e5\u5728 --processes \u53c2\u6570\u540e\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u7684\u6570\u503c\uff0c\u5219\u542f\u52a8\u7684 slave \u4e2a\u6570\u4e0e\u673a\u5668\u7684 CPU \u6838\u6570\u76f8\u540c\u3002 $ locusts -f examples/first-testcase.yml --processes 4 [ 2017 -08-26 23 :51:47,071 ] bogon/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-26 23 :51:47,075 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,078 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,080 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,083 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.runners: Client 'bogon_656e0af8e968a8533d379dd252422ad3' reported as ready. Currently 1 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_09f73850252ee4ec739ed77d3c4c6dba' reported as ready. Currently 2 clients ready to swarm. [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_869f7ed671b1a9952b56610f01e2006f' reported as ready. Currently 3 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_80a804cda36b80fac17b57fd2d5e7cdb' reported as ready. Currently 4 clients ready to swarm. Enjoy!","title":"\u6027\u80fd\u6d4b\u8bd5"},{"location":"run-tests/load-test/#_1","text":"","title":"\u539f\u7406\u56fe"},{"location":"run-tests/load-test/#_2","text":"\u5b89\u88c5\u5b8c\u6210 HttpRunner \u540e\uff0c\u7cfb\u7edf\u4e2d\u4f1a\u65b0\u589e locusts \u547d\u4ee4\uff0c\u4f46\u4e0d\u4f1a\u540c\u65f6\u5b89\u88c5 Locust\u3002 \u5728\u7cfb\u7edf\u4e2d\u672a\u5b89\u88c5 Locust \u7684\u60c5\u51b5\u4e0b\uff0c\u8fd0\u884c locusts \u547d\u4ee4\u65f6\u4f1a\u51fa\u73b0\u5982\u4e0b\u63d0\u793a\u3002 $ locusts -V WARNING Locust is not installed, install first and try again. install command: pip install locustio Locust \u7684\u5b89\u88c5\u65b9\u5f0f\u5982\u4e0b\uff1a $ pip install locustio \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u6267\u884c locusts -V \u53ef\u67e5\u770b\u5230 Locust \u7684\u7248\u672c\u53f7\u3002 $ locusts -V [2017-08-26 23:45:42,246] bogon/INFO/stdout: Locust 0.8a2 [2017-08-26 23:45:42,246] bogon/INFO/stdout: \u6267\u884c locusts -h \uff0c\u53ef\u67e5\u770b\u5230\u4f7f\u7528\u5e2e\u52a9\u6587\u6863\u3002 $ locusts -h Usage: locust [options] [LocustClass [LocustClass2 ... ]] Options: -h, --help show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33 --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE Store current request stats to files in CSV format. --master Set locust to run in distributed mode with this process as master --slave Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats --no-reset-stats Do not reset statistics once hatching has been completed -l, --list Show list of possible locust classes and exit --show-task-ratio print table of the locust classes' task execution ratio --show-task-ratio-json print json data of the locust classes' task execution ratio -V, --version show program's version number and exit \u53ef\u4ee5\u770b\u51fa\uff0c loucsts \u547d\u4ee4\u4e0e locust \u547d\u4ee4\u7684\u7528\u6cd5\u57fa\u672c\u76f8\u540c\u3002 \u76f8\u6bd4\u4e8e locust \u547d\u4ee4\uff0c loucsts \u547d\u4ee4\u4e3b\u8981\u5b58\u5728\u5982\u4e0b\u4e24\u9879\u5dee\u5f02\u3002","title":"\u5b89\u88c5\u4f9d\u8d56\u5305"},{"location":"run-tests/load-test/#_3","text":"\u5728 -f \u53c2\u6570\u540e\u9762\uff0c loucsts \u547d\u4ee4\u4e0d\u4ec5\u53ef\u4ee5\u6307\u5b9a Locust \u652f\u6301\u7684 Python \u6587\u4ef6\uff0c\u540c\u65f6\u53ef\u4ee5\u76f4\u63a5\u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002\u5728\u5177\u4f53\u5b9e\u73b0\u4e0a\uff0c\u5f53 -f \u6307\u5b9a YAML/JSON \u683c\u5f0f\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u65f6\uff0c\u4f1a\u5148\u5c06\u5176\u8f6c\u6362\u4e3a Python \u683c\u5f0f\u7684 locustfile\uff0c\u7136\u540e\u518d\u5c06 locustfile.py \u4f20\u7ed9 locust \u547d\u4ee4\u3002 $ locusts -f examples/first-testcase.yml [ 2017 -08-18 17 :20:43,915 ] Leos-MacBook-Air.local/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-18 17 :20:43,918 ] Leos-MacBook-Air.local/INFO/locust.main: Starting Locust 0 .8a2 \u6267\u884c\u4e0a\u8ff0\u547d\u4ee4\u540e\uff0c\u5373\u5b8c\u6210\u4e86 Locust \u670d\u52a1\u7684\u542f\u52a8\uff0c\u540e\u7eed\u5c31\u53ef\u4ee5\u5728 Locust \u7684 Web \u7ba1\u7406\u754c\u9762\u4e2d\u8fdb\u884c\u64cd\u4f5c\u4e86\uff0c\u4f7f\u7528\u65b9\u5f0f\u4e0e Locust \u5b8c\u5168\u76f8\u540c\u3002","title":"\u8fd0\u884c\u6027\u80fd\u6d4b\u8bd5"},{"location":"run-tests/load-test/#_4","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5728 Locust \u4e2d\u5982\u9700\u4f7f\u7528 master-slave \u6a21\u5f0f\u542f\u52a8\u591a\u4e2a\u8fdb\u7a0b\uff08\u4f7f\u7528\u591a\u6838\u5904\u7406\u5668\u7684\u80fd\u529b\uff09\uff0c\u53ea\u80fd\u5148\u542f\u52a8 master\uff0c\u7136\u540e\u518d\u9010\u4e00\u542f\u52a8\u82e5\u5e72\u4e2a slave\u3002 $ locust -f locustfile.py --master $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & $ locust -f locustfile.py --slave & \u5728 HttpRunner \u4e2d\uff0c\u65b0\u589e\u5b9e\u73b0 --processes \u53c2\u6570\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u542f\u52a8 1 \u4e2a master \u548c\u591a\u4e2a salve\u3002\u82e5\u5728 --processes \u53c2\u6570\u540e\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u7684\u6570\u503c\uff0c\u5219\u542f\u52a8\u7684 slave \u4e2a\u6570\u4e0e\u673a\u5668\u7684 CPU \u6838\u6570\u76f8\u540c\u3002 $ locusts -f examples/first-testcase.yml --processes 4 [ 2017 -08-26 23 :51:47,071 ] bogon/INFO/locust.main: Starting web monitor at *:8089 [ 2017 -08-26 23 :51:47,075 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,078 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,080 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,083 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.runners: Client 'bogon_656e0af8e968a8533d379dd252422ad3' reported as ready. Currently 1 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_09f73850252ee4ec739ed77d3c4c6dba' reported as ready. Currently 2 clients ready to swarm. [ 2017 -08-26 23 :51:47,084 ] bogon/INFO/locust.main: Starting Locust 0 .8a2 [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_869f7ed671b1a9952b56610f01e2006f' reported as ready. Currently 3 clients ready to swarm. [ 2017 -08-26 23 :51:47,085 ] bogon/INFO/locust.runners: Client 'bogon_80a804cda36b80fac17b57fd2d5e7cdb' reported as ready. Currently 4 clients ready to swarm. Enjoy!","title":"\u591a\u8fdb\u7a0b\u8fd0\u884c\u6a21\u5f0f"},{"location":"run-tests/report/","text":"\u4f7f\u7528 HttpRunner \u6267\u884c\u5b8c\u81ea\u52a8\u5316\u6d4b\u8bd5\u540e\uff0c\u4f1a\u5728\u5f53\u524d\u8def\u5f84\u7684 reports \u76ee\u5f55\u4e0b\u751f\u6210\u4e00\u4efd HTML \u683c\u5f0f\u7684\u6d4b\u8bd5\u62a5\u544a\u3002 \u9ed8\u8ba4\u60c5\u51b5 \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u5f00\u59cb\u7684\u65f6\u95f4\u6233\u3002 $ hrun docs/data/demo-quickstart-6.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200 , response_time ( ms ) : 10 .05 ms, response_length: 46 bytes . /api/users/1548561170497 INFO POST http://127.0.0.1:5000/api/users/1548561170497 INFO status_code: 201 , response_time ( ms ) : 2 .88 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0 .034s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548561170.html \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002 \u9ed8\u8ba4\u62a5\u544a\u6837\u5f0f \u00b6 \u5728 HttpRunner \u4e2d\u81ea\u5e26\u4e86\u4e00\u4e2a Jinja2 \u683c\u5f0f\u7684\u62a5\u544a\u6a21\u7248\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u62a5\u544a\u6837\u5f0f\u5747\u57fa\u4e8e\u8be5\u6a21\u7248\uff08 httprunner/templates/default_report_template.html \uff09\u3002 \u6d4b\u8bd5\u62a5\u544a\u5f62\u5f0f\u5982\u4e0b\uff1a \u5728 Summary \u4e2d\uff0c\u4f1a\u7f57\u5217\u672c\u6b21\u6d4b\u8bd5\u7684\u6574\u4f53\u4fe1\u606f\uff0c\u5305\u62ec\u6d4b\u8bd5\u5f00\u59cb\u65f6\u95f4\u3001\u603b\u8fd0\u884c\u65f6\u957f\u3001\u8fd0\u884c\u7684Python\u7248\u672c\u548c\u7cfb\u7edf\u73af\u5883\u3001\u8fd0\u884c\u7ed3\u679c\u7edf\u8ba1\u6570\u636e\u3002 \u5728 Details \u4e2d\uff0c\u4f1a\u8be6\u7ec6\u5c55\u793a\u6bcf\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u7ed3\u679c\u3002 \u70b9\u51fb\u6d4b\u8bd5\u7528\u4f8b\u5bf9\u5e94\u7684 log \u6309\u94ae\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u8be5\u7528\u4f8b\u6267\u884c\u7684\u8be6\u7ec6\u6570\u636e\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 headers \u548c body\u3001\u54cd\u5e94\u7684 headers \u548c body\u3001\u6821\u9a8c\u7ed3\u679c\u3001\u54cd\u5e94\u3001\u54cd\u5e94\u8017\u65f6\uff08elapsed\uff09\u7b49\u4fe1\u606f\u3002 \u82e5\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u4e0d\u6210\u529f\uff08failed/error/skipped\uff09\uff0c\u5219\u5728\u8be5\u6d4b\u8bd5\u7528\u4f8b\u7684 detail \u4e2d\u4f1a\u51fa\u73b0 traceback \u6309\u94ae\uff0c\u70b9\u51fb\u8be5\u6309\u94ae\u540e\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u5931\u8d25\u7684\u5806\u6808\u65e5\u5fd7\uff0c\u6216\u8005 skipped \u7684\u539f\u56e0\u3002 \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002 \u81ea\u5b9a\u4e49 \u00b6 \u9664\u4e86\u9ed8\u8ba4\u7684\u62a5\u544a\u6837\u5f0f\uff0cHttpRunner \u8fd8\u652f\u6301\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u62a5\u544a\u6a21\u677f\u3002 \u7f16\u5199\u81ea\u5b9a\u4e49\u6a21\u677f\uff08Jinja2\u683c\u5f0f\uff09 \u00b6 \u81ea\u5b9a\u4e49\u6a21\u677f\u9700\u8981\u91c7\u7528 Jinja2 \u7684\u683c\u5f0f\uff0c\u5176\u4e2d\u53ef\u4ee5\u4f7f\u7528\u7684\u6570\u636e\u53ef\u53c2\u8003 \u6570\u636e\u7ed3\u6784\u793a\u4f8b \u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u81ea\u5b9a\u4e49\u6a21\u677f\u4e2d\u5c55\u793a\u6d4b\u8bd5\u7ed3\u679c\u7684\u7edf\u8ba1\u6570\u636e\uff0c\u5c31\u53ef\u4ee5\u91c7\u7528\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u63cf\u8ff0\uff1a < tr > < th > TOTAL th > < th > SUCCESS th > < th > FAILED th > < th > ERROR th > < th > SKIPPED th > tr > < tr > < td > {{stat.testsRun}} td > < td > {{stat.successes}} td > < td > {{stat.failures}} td > < td > {{stat.errors}} td > < td > {{stat.skipped}} td > tr > \u5728\u81ea\u5b9a\u4e49\u62a5\u544a\u6a21\u677f\u65f6\uff0c\u53ef\u4ee5\u53c2\u8003 HttpRunner \u7684 \u9ed8\u8ba4\u62a5\u544a\u6a21\u677f \uff0c\u8981\u5b9e\u73b0\u66f4\u590d\u6742\u7684\u6a21\u7248\u529f\u80fd\uff0c\u53ef\u53c2\u8003 Jinja2 \u7684\u4f7f\u7528\u6587\u6863\u3002 \u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u677f \u00b6 \u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u7248\u65f6\uff0c\u9700\u8981\u901a\u8fc7 --report-template \u6307\u5b9a\u62a5\u544a\u6a21\u677f\u7684\u8def\u5f84\uff0c\u7136\u540e\u6d4b\u8bd5\u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u5c31\u4f1a\u91c7\u7528\u81ea\u5b9a\u4e49\u7684\u6a21\u677f\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u3002 $ hrun docs/data/demo-quickstart-2.yml --report-template /path/to/custom_report_template ... \u540c\u4e0a\uff0c\u7701\u7565 INFO render with html report template: /path/to/custom_report_template INFO Start to render Html report ... INFO Generated Html report: reports/1532078874.html \u6307\u5b9a\u62a5\u544a\u751f\u6210\u8def\u5f84 \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\u3002\u5982\u9700\u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u8def\u5f84\uff0c\u53ef\u4ee5\u4f7f\u7528 --report-dir \u53c2\u6570\u3002 $ hrun docs/data/demo-quickstart-2.yml --dirreport-name /other/path/ ... \u540c\u4e0a\uff0c\u7701\u7565 INFO Start to render Html report ... INFO Generated Html report: /other/path/1532078874.html","title":"\u6d4b\u8bd5\u62a5\u544a"},{"location":"run-tests/report/#_1","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\uff0c\u6587\u4ef6\u540d\u79f0\u4e3a\u6d4b\u8bd5\u5f00\u59cb\u7684\u65f6\u95f4\u6233\u3002 $ hrun docs/data/demo-quickstart-6.yml INFO Start to run testcase: testcase description /api/get-token INFO POST http://127.0.0.1:5000/api/get-token INFO status_code: 200 , response_time ( ms ) : 10 .05 ms, response_length: 46 bytes . /api/users/1548561170497 INFO POST http://127.0.0.1:5000/api/users/1548561170497 INFO status_code: 201 , response_time ( ms ) : 2 .88 ms, response_length: 54 bytes . ---------------------------------------------------------------------- Ran 2 tests in 0 .034s OK INFO Start to render Html report ... INFO Generated Html report: /Users/debugtalk/MyProjects/HttpRunner-dev/httprunner-docs-v2x/reports/1548561170.html \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002","title":"\u9ed8\u8ba4\u60c5\u51b5"},{"location":"run-tests/report/#_2","text":"\u5728 HttpRunner \u4e2d\u81ea\u5e26\u4e86\u4e00\u4e2a Jinja2 \u683c\u5f0f\u7684\u62a5\u544a\u6a21\u7248\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u62a5\u544a\u6837\u5f0f\u5747\u57fa\u4e8e\u8be5\u6a21\u7248\uff08 httprunner/templates/default_report_template.html \uff09\u3002 \u6d4b\u8bd5\u62a5\u544a\u5f62\u5f0f\u5982\u4e0b\uff1a \u5728 Summary \u4e2d\uff0c\u4f1a\u7f57\u5217\u672c\u6b21\u6d4b\u8bd5\u7684\u6574\u4f53\u4fe1\u606f\uff0c\u5305\u62ec\u6d4b\u8bd5\u5f00\u59cb\u65f6\u95f4\u3001\u603b\u8fd0\u884c\u65f6\u957f\u3001\u8fd0\u884c\u7684Python\u7248\u672c\u548c\u7cfb\u7edf\u73af\u5883\u3001\u8fd0\u884c\u7ed3\u679c\u7edf\u8ba1\u6570\u636e\u3002 \u5728 Details \u4e2d\uff0c\u4f1a\u8be6\u7ec6\u5c55\u793a\u6bcf\u4e00\u6761\u6d4b\u8bd5\u7528\u4f8b\u7684\u8fd0\u884c\u7ed3\u679c\u3002 \u70b9\u51fb\u6d4b\u8bd5\u7528\u4f8b\u5bf9\u5e94\u7684 log \u6309\u94ae\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u8be5\u7528\u4f8b\u6267\u884c\u7684\u8be6\u7ec6\u6570\u636e\uff0c\u5305\u62ec\u8bf7\u6c42\u7684 headers \u548c body\u3001\u54cd\u5e94\u7684 headers \u548c body\u3001\u6821\u9a8c\u7ed3\u679c\u3001\u54cd\u5e94\u3001\u54cd\u5e94\u8017\u65f6\uff08elapsed\uff09\u7b49\u4fe1\u606f\u3002 \u82e5\u6d4b\u8bd5\u7528\u4f8b\u8fd0\u884c\u4e0d\u6210\u529f\uff08failed/error/skipped\uff09\uff0c\u5219\u5728\u8be5\u6d4b\u8bd5\u7528\u4f8b\u7684 detail \u4e2d\u4f1a\u51fa\u73b0 traceback \u6309\u94ae\uff0c\u70b9\u51fb\u8be5\u6309\u94ae\u540e\uff0c\u4f1a\u5728\u5f39\u51fa\u6846\u4e2d\u5c55\u793a\u5931\u8d25\u7684\u5806\u6808\u65e5\u5fd7\uff0c\u6216\u8005 skipped \u7684\u539f\u56e0\u3002 \u70b9\u51fb\u67e5\u770b \u6d4b\u8bd5\u62a5\u544a \u3002","title":"\u9ed8\u8ba4\u62a5\u544a\u6837\u5f0f"},{"location":"run-tests/report/#_3","text":"\u9664\u4e86\u9ed8\u8ba4\u7684\u62a5\u544a\u6837\u5f0f\uff0cHttpRunner \u8fd8\u652f\u6301\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u62a5\u544a\u6a21\u677f\u3002","title":"\u81ea\u5b9a\u4e49"},{"location":"run-tests/report/#jinja2","text":"\u81ea\u5b9a\u4e49\u6a21\u677f\u9700\u8981\u91c7\u7528 Jinja2 \u7684\u683c\u5f0f\uff0c\u5176\u4e2d\u53ef\u4ee5\u4f7f\u7528\u7684\u6570\u636e\u53ef\u53c2\u8003 \u6570\u636e\u7ed3\u6784\u793a\u4f8b \u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u9700\u8981\u5728\u81ea\u5b9a\u4e49\u6a21\u677f\u4e2d\u5c55\u793a\u6d4b\u8bd5\u7ed3\u679c\u7684\u7edf\u8ba1\u6570\u636e\uff0c\u5c31\u53ef\u4ee5\u91c7\u7528\u5982\u4e0b\u65b9\u5f0f\u8fdb\u884c\u63cf\u8ff0\uff1a < tr > < th > TOTAL th > < th > SUCCESS th > < th > FAILED th > < th > ERROR th > < th > SKIPPED th > tr > < tr > < td > {{stat.testsRun}} td > < td > {{stat.successes}} td > < td > {{stat.failures}} td > < td > {{stat.errors}} td > < td > {{stat.skipped}} td > tr > \u5728\u81ea\u5b9a\u4e49\u62a5\u544a\u6a21\u677f\u65f6\uff0c\u53ef\u4ee5\u53c2\u8003 HttpRunner \u7684 \u9ed8\u8ba4\u62a5\u544a\u6a21\u677f \uff0c\u8981\u5b9e\u73b0\u66f4\u590d\u6742\u7684\u6a21\u7248\u529f\u80fd\uff0c\u53ef\u53c2\u8003 Jinja2 \u7684\u4f7f\u7528\u6587\u6863\u3002","title":"\u7f16\u5199\u81ea\u5b9a\u4e49\u6a21\u677f\uff08Jinja2\u683c\u5f0f\uff09"},{"location":"run-tests/report/#_4","text":"\u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u7248\u65f6\uff0c\u9700\u8981\u901a\u8fc7 --report-template \u6307\u5b9a\u62a5\u544a\u6a21\u677f\u7684\u8def\u5f84\uff0c\u7136\u540e\u6d4b\u8bd5\u8fd0\u884c\u5b8c\u6210\u540e\uff0c\u5c31\u4f1a\u91c7\u7528\u81ea\u5b9a\u4e49\u7684\u6a21\u677f\u751f\u6210\u6d4b\u8bd5\u62a5\u544a\u3002 $ hrun docs/data/demo-quickstart-2.yml --report-template /path/to/custom_report_template ... \u540c\u4e0a\uff0c\u7701\u7565 INFO render with html report template: /path/to/custom_report_template INFO Start to render Html report ... INFO Generated Html report: reports/1532078874.html","title":"\u4f7f\u7528\u81ea\u5b9a\u4e49\u6a21\u677f"},{"location":"run-tests/report/#_5","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u751f\u6210\u7684\u6d4b\u8bd5\u62a5\u544a\u6587\u4ef6\u4f1a\u4f4d\u4e8e\u9879\u76ee\u6839\u76ee\u5f55\u7684 reports \u6587\u4ef6\u5939\u4e2d\u3002\u5982\u9700\u6307\u5b9a\u751f\u6210\u62a5\u544a\u7684\u8def\u5f84\uff0c\u53ef\u4ee5\u4f7f\u7528 --report-dir \u53c2\u6570\u3002 $ hrun docs/data/demo-quickstart-2.yml --dirreport-name /other/path/ ... \u540c\u4e0a\uff0c\u7701\u7565 INFO Start to render Html report ... INFO Generated Html report: /other/path/1532078874.html","title":"\u6307\u5b9a\u62a5\u544a\u751f\u6210\u8def\u5f84"}]} \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 925d1404..4a1bc4d0 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ