diff --git a/images/httprunner-formats.png b/images/httprunner-formats.png
new file mode 100644
index 00000000..e4e8b1ed
Binary files /dev/null and b/images/httprunner-formats.png differ
diff --git a/images/httprunner-step-request-validate.png b/images/httprunner-step-request-validate.png
new file mode 100644
index 00000000..a837da8d
Binary files /dev/null and b/images/httprunner-step-request-validate.png differ
diff --git a/search/search_index.json b/search/search_index.json
index 68b5d936..45a73284 100644
--- a/search/search_index.json
+++ b/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"HttpRunner \u00b6 HttpRunner is a simple & elegant, yet powerful HTTP(S) testing framework. Enjoy! \u2728 \ud83d\ude80 \u2728 This docs site is corresponding to the latest version 3.x , for 2.x you can reference archive link . Design Philosophy \u00b6 Convention over configuration ROI matters Embrace open source, leverage requests , pytest , pydantic , allure and locust . Key Features \u00b6 Inherit all powerful features of requests , just have fun to handle HTTP(S) in human way. Define testcase in YAML or JSON format, run with pytest in concise and elegant manner. Record and generate testcases with HAR support. Supports variables / extract / validate / hooks mechanisms to create extremely complex test scenarios. With debugtalk.py plugin, any function can be used in any part of your testcase. With jmespath , extract and validate json response has never been easier. With pytest , hundreds of plugins are readily available. With allure , test report can be pretty nice and powerful. With reuse of locust , you can run performance test without extra work. CLI command supported, perfect combination with CI/CD . Subscribe \u00b6 \u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"Introduction"},{"location":"#httprunner","text":"HttpRunner is a simple & elegant, yet powerful HTTP(S) testing framework. Enjoy! \u2728 \ud83d\ude80 \u2728 This docs site is corresponding to the latest version 3.x , for 2.x you can reference archive link .","title":"HttpRunner"},{"location":"#design-philosophy","text":"Convention over configuration ROI matters Embrace open source, leverage requests , pytest , pydantic , allure and locust .","title":"Design Philosophy"},{"location":"#key-features","text":"Inherit all powerful features of requests , just have fun to handle HTTP(S) in human way. Define testcase in YAML or JSON format, run with pytest in concise and elegant manner. Record and generate testcases with HAR support. Supports variables / extract / validate / hooks mechanisms to create extremely complex test scenarios. With debugtalk.py plugin, any function can be used in any part of your testcase. With jmespath , extract and validate json response has never been easier. With pytest , hundreds of plugins are readily available. With allure , test report can be pretty nice and powerful. With reuse of locust , you can run performance test without extra work. CLI command supported, perfect combination with CI/CD .","title":"Key Features"},{"location":"#subscribe","text":"\u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"Subscribe"},{"location":"CHANGELOG/","text":"Release History \u00b6 3.0.13 (2020-06-15) \u00b6 Fixed fix: avoid '.csv' been converted to '_csv' fix: convert har to JSON format testcase fix: missing ${var} handling in overriding config variables fix: SyntaxError caused by quote in case of headers.\"Set-Cookie\" fix: FileExistsError when specified project name conflicts with existed file fix: testcase path handling error when path startswith \"./\" or \".\\\" 3.0.12 (2020-06-14) \u00b6 Fixed fix: compatibility with different path separators of Linux and Windows fix: IndexError in ensure_file_path_valid when file_path=os.getcwd() fix: ensure step referenced api, convert to v3 testcase fix: several other compatibility issues Changed change: skip reporting sentry for errors occurred in debugtalk.py 3.0.11 (2020-06-08) \u00b6 Changed change: override variables (1) testcase: session variables > step variables > config variables (2) testsuite: testcase variables > config variables (3) testsuite testcase variables > testcase config variables Fixed fix: incorrect summary success when testcase failed fix: reload to refresh previously loaded debugtalk module fix: escape $$ in variable value 3.0.10 (2020-06-07) \u00b6 Added feat: implement step setup/teardown hooks feat: support alter response in teardown hooks Fixed fix: ensure upload ready fix: add ExtendJSONEncoder to safely dump json data with python object, such as MultipartEncoder 3.0.9 (2020-06-07) \u00b6 Fixed fix: miss formatting referenced testcase fix: handle cases when parent directory name includes dot/hyphen/space Changed change: add export keyword in TStep to export session variables from referenced testcase change: rename TestCaseInOut field, config_vars and export_vars change: rename StepData field, export_vars change: add --tb=short for hrun command to use shorter traceback format by default change: search debugtalk.py upward recursively until system root dir 3.0.8 (2020-06-04) \u00b6 Added feat: add sentry sdk feat: extract session variable from referenced testcase step Fixed fix: missing request json fix: override testsuite/testcase config verify fix: only strip whitespaces and tabs, \\n\\r are left because they maybe used in changeset fix: log testcase duration before raise ValidationFailure Changed change: add httprunner version in generated pytest file 3.0.7 (2020-06-03) \u00b6 Added feat: make pytest files in chain style feat: hrun supports run pytest files feat: get raw testcase model from pytest file Fixed fix: convert jmespath.search result to int/float unintentionally fix: referenced testcase should not be run duplicately fix: requests.cookies.CookieConflictError, multiple cookies with name fix: missing exit code from pytest fix: skip invalid testcase/testsuite yaml/json file Changed change: har2case generate pytest file by default docs: update sponsor info 3.0.6 (2020-05-29) \u00b6 Added feat: make referenced testcase as pytest class Fixed fix: ensure converted python file in utf-8 encoding fix: duplicate running referenced testcase fix: ensure compatibility issues between testcase format v2 and v3 fix: ensure compatibility with deprecated cli args in v2, include --failfast/--report-file/--save-tests fix: UnicodeDecodeError when request body in protobuf Changed change: make allure-pytest , requests-toolbelt , filetype as optional dependencies change: move all unittests to tests folder change: save testcase log in PWD/logs/ directory 3.0.5 (2020-05-22) \u00b6 Added feat: each testcase has an unique id in uuid4 format feat: add default header HRUN-Request-ID for each testcase #721 feat: builtin allure report feat: dump log for each testcase Fixed fix: ensure referenced testcase share the same session Changed change: remove default added -s option for hrun 3.0.4 (2020-05-19) \u00b6 Added feat: make testsuite and run testsuite feat: testcase/testsuite config support getting variables by function feat: har2case with request cookies feat: log request/response headers and body with indent Fixed fix: extract response cookies fix: handle errors when no valid testcases generated Changed change: har2case do not ignore request headers, except for header startswith : 3.0.3 (2020-05-17) \u00b6 Fixed fix: compatibility with testcase file path includes dots, space and minus sign fix: testcase generator, validate content.xxx => body.xxx fix: scaffold for v3 3.0.2 (2020-05-16) \u00b6 Added feat: add make sub-command to generate python testcases from YAML/JSON feat: format generated python testcases with black test: add postman echo & httpbin as testcase examples Changed refactor all replace jsonschema validation with pydantic remove compatibility with testcase/testsuite format v1 replace unittest with pytest remove builtin html report, allure will be used with pytest later remove locust support temporarily update command line interface 3.0.1 (2020-03-24) \u00b6 Changed remove sentry sdk 3.0.0 (2020-03-10) \u00b6 Added feat: dump log for each testcase feat: add default header HRUN-Request-ID for each testcase #721 Changed remove support for Python 2.7 replace logging with loguru replace string format with f-string remove dependency colorama and colorlog generate reports/logs folder in current working directory remove cli --validate remove cli --pretty","title":"CHANGELOG"},{"location":"CHANGELOG/#release-history","text":"","title":"Release History"},{"location":"CHANGELOG/#3013-2020-06-15","text":"Fixed fix: avoid '.csv' been converted to '_csv' fix: convert har to JSON format testcase fix: missing ${var} handling in overriding config variables fix: SyntaxError caused by quote in case of headers.\"Set-Cookie\" fix: FileExistsError when specified project name conflicts with existed file fix: testcase path handling error when path startswith \"./\" or \".\\\"","title":"3.0.13 (2020-06-15)"},{"location":"CHANGELOG/#3012-2020-06-14","text":"Fixed fix: compatibility with different path separators of Linux and Windows fix: IndexError in ensure_file_path_valid when file_path=os.getcwd() fix: ensure step referenced api, convert to v3 testcase fix: several other compatibility issues Changed change: skip reporting sentry for errors occurred in debugtalk.py","title":"3.0.12 (2020-06-14)"},{"location":"CHANGELOG/#3011-2020-06-08","text":"Changed change: override variables (1) testcase: session variables > step variables > config variables (2) testsuite: testcase variables > config variables (3) testsuite testcase variables > testcase config variables Fixed fix: incorrect summary success when testcase failed fix: reload to refresh previously loaded debugtalk module fix: escape $$ in variable value","title":"3.0.11 (2020-06-08)"},{"location":"CHANGELOG/#3010-2020-06-07","text":"Added feat: implement step setup/teardown hooks feat: support alter response in teardown hooks Fixed fix: ensure upload ready fix: add ExtendJSONEncoder to safely dump json data with python object, such as MultipartEncoder","title":"3.0.10 (2020-06-07)"},{"location":"CHANGELOG/#309-2020-06-07","text":"Fixed fix: miss formatting referenced testcase fix: handle cases when parent directory name includes dot/hyphen/space Changed change: add export keyword in TStep to export session variables from referenced testcase change: rename TestCaseInOut field, config_vars and export_vars change: rename StepData field, export_vars change: add --tb=short for hrun command to use shorter traceback format by default change: search debugtalk.py upward recursively until system root dir","title":"3.0.9 (2020-06-07)"},{"location":"CHANGELOG/#308-2020-06-04","text":"Added feat: add sentry sdk feat: extract session variable from referenced testcase step Fixed fix: missing request json fix: override testsuite/testcase config verify fix: only strip whitespaces and tabs, \\n\\r are left because they maybe used in changeset fix: log testcase duration before raise ValidationFailure Changed change: add httprunner version in generated pytest file","title":"3.0.8 (2020-06-04)"},{"location":"CHANGELOG/#307-2020-06-03","text":"Added feat: make pytest files in chain style feat: hrun supports run pytest files feat: get raw testcase model from pytest file Fixed fix: convert jmespath.search result to int/float unintentionally fix: referenced testcase should not be run duplicately fix: requests.cookies.CookieConflictError, multiple cookies with name fix: missing exit code from pytest fix: skip invalid testcase/testsuite yaml/json file Changed change: har2case generate pytest file by default docs: update sponsor info","title":"3.0.7 (2020-06-03)"},{"location":"CHANGELOG/#306-2020-05-29","text":"Added feat: make referenced testcase as pytest class Fixed fix: ensure converted python file in utf-8 encoding fix: duplicate running referenced testcase fix: ensure compatibility issues between testcase format v2 and v3 fix: ensure compatibility with deprecated cli args in v2, include --failfast/--report-file/--save-tests fix: UnicodeDecodeError when request body in protobuf Changed change: make allure-pytest , requests-toolbelt , filetype as optional dependencies change: move all unittests to tests folder change: save testcase log in PWD/logs/ directory","title":"3.0.6 (2020-05-29)"},{"location":"CHANGELOG/#305-2020-05-22","text":"Added feat: each testcase has an unique id in uuid4 format feat: add default header HRUN-Request-ID for each testcase #721 feat: builtin allure report feat: dump log for each testcase Fixed fix: ensure referenced testcase share the same session Changed change: remove default added -s option for hrun","title":"3.0.5 (2020-05-22)"},{"location":"CHANGELOG/#304-2020-05-19","text":"Added feat: make testsuite and run testsuite feat: testcase/testsuite config support getting variables by function feat: har2case with request cookies feat: log request/response headers and body with indent Fixed fix: extract response cookies fix: handle errors when no valid testcases generated Changed change: har2case do not ignore request headers, except for header startswith :","title":"3.0.4 (2020-05-19)"},{"location":"CHANGELOG/#303-2020-05-17","text":"Fixed fix: compatibility with testcase file path includes dots, space and minus sign fix: testcase generator, validate content.xxx => body.xxx fix: scaffold for v3","title":"3.0.3 (2020-05-17)"},{"location":"CHANGELOG/#302-2020-05-16","text":"Added feat: add make sub-command to generate python testcases from YAML/JSON feat: format generated python testcases with black test: add postman echo & httpbin as testcase examples Changed refactor all replace jsonschema validation with pydantic remove compatibility with testcase/testsuite format v1 replace unittest with pytest remove builtin html report, allure will be used with pytest later remove locust support temporarily update command line interface","title":"3.0.2 (2020-05-16)"},{"location":"CHANGELOG/#301-2020-03-24","text":"Changed remove sentry sdk","title":"3.0.1 (2020-03-24)"},{"location":"CHANGELOG/#300-2020-03-10","text":"Added feat: dump log for each testcase feat: add default header HRUN-Request-ID for each testcase #721 Changed remove support for Python 2.7 replace logging with loguru replace string format with f-string remove dependency colorama and colorlog generate reports/logs folder in current working directory remove cli --validate remove cli --pretty","title":"3.0.0 (2020-03-10)"},{"location":"installation/","text":"HttpRunner is developed with Python, it supports Python 3.6+ and most operating systems. Combination of Python 3.6/3.7/3.8 and macOS/Linux/Windows are tested continuously on GitHub-Actions . Installation \u00b6 HttpRunner is available on PyPI and can be installed through pip . $ pip3 install httprunner If you want to keep up with the latest version, you can install with github repository url. $ pip3 install git+https://github.com/httprunner/httprunner.git@master If\b you have installed HttpRunner before and want to upgrade to the latest version, you can use the -U option. $ pip3 install -U httprunner $ pip3 install -U git+https://github.com/httprunner/httprunner.git@master Check Installation \u00b6 When HttpRunner is installed, 4 commands will be added in your system. httprunner : main command, used for all functions hrun : alias for httprunner run , used to run YAML/JSON/pytest testcases hmake : alias for httprunner make , used to convert YAML/JSON testcases to pytest files har2case : alias for httprunner har2case , used to convert HAR to YAML/JSON testcases To see HttpRunner version: $ httprunner -V # hrun -V 3.0.10 To see available options, run: $ httprunner -h usage: httprunner [-h] [-V] {run,startproject,har2case,make} ... One-stop solution for HTTP(S) testing. positional arguments: {run,startproject,har2case,make} sub-command help run Make HttpRunner testcases and run with pytest. startproject Create a new project with template structure. har2case Convert HAR(HTTP Archive) to YAML/JSON testcases for HttpRunner. make Convert YAML/JSON testcases to pytest cases. optional arguments: -h, --help show this help message and exit -V, --version show version","title":"Installation"},{"location":"installation/#installation","text":"HttpRunner is available on PyPI and can be installed through pip . $ pip3 install httprunner If you want to keep up with the latest version, you can install with github repository url. $ pip3 install git+https://github.com/httprunner/httprunner.git@master If\b you have installed HttpRunner before and want to upgrade to the latest version, you can use the -U option. $ pip3 install -U httprunner $ pip3 install -U git+https://github.com/httprunner/httprunner.git@master","title":"Installation"},{"location":"installation/#check-installation","text":"When HttpRunner is installed, 4 commands will be added in your system. httprunner : main command, used for all functions hrun : alias for httprunner run , used to run YAML/JSON/pytest testcases hmake : alias for httprunner make , used to convert YAML/JSON testcases to pytest files har2case : alias for httprunner har2case , used to convert HAR to YAML/JSON testcases To see HttpRunner version: $ httprunner -V # hrun -V 3.0.10 To see available options, run: $ httprunner -h usage: httprunner [-h] [-V] {run,startproject,har2case,make} ... One-stop solution for HTTP(S) testing. positional arguments: {run,startproject,har2case,make} sub-command help run Make HttpRunner testcases and run with pytest. startproject Create a new project with template structure. har2case Convert HAR(HTTP Archive) to YAML/JSON testcases for HttpRunner. make Convert YAML/JSON testcases to pytest cases. optional arguments: -h, --help show this help message and exit -V, --version show version","title":"Check Installation"},{"location":"quickstart/","text":"Quick Start \u00b6 First of all, remember HttpRunner is a simple yet powerful HTTP(S) testing framework. This document will help you to learn HttpRunner in 10 minutes. Write the first test case \u00b6 Open your favorite text editor and you can write test cases like this. - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : F8prvGryC5beBr4g json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, each API request is described in a test block. And in the request field, it describes the detail of HTTP request, includes url, method, headers and data, which are in line with the captured traffic. You may wonder why we use the json field other than data . That's because the post data is in JSON format, when we use json to indicate the post data, we do not have to specify Content-Type to be application/json in request headers or dump data before request. Have you recalled some familiar scenes? Yes! That's what we did in requests.request ! Since HttpRunner takes full reuse of Requests , it inherits all powerful features of Requests , and we can handle HTTP request as the way we do before. Run test cases \u00b6 Suppose the test case file is named as quickstart-demo-rev-0.yml and is located in examples folder, then we can run it in this way. ate examples/demo-rev-0.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 48 ms, response_length: 46 bytes OK (0.049669)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 ERROR:root: Failed to POST http://127.0.0.1:5000/api/users/1000! exception msg: 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR (0.006471)s ---------------------------------------------------------------------- Ran 2 tests in 0.056s FAILED (Errors=1) Oops! The second test case failed with 403 status code. That is because we request with the same data as we captured in Charles Proxy , while the token is generated dynamically, thus the recorded data can not be be used twice directly. Optimize test case: correlation \u00b6 To fix this problem, we should correlate token field in the second API test case, which is also called correlation . - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, the token field is no longer hardcoded, instead it is extracted from the first API request with extract mechanism. In the meanwhile, it is assigned to token variable, which can be referenced by the subsequent API requests. Now we save the test cases to quickstart-demo-rev-1.yml and rerun it, and we will find that both API requests to be successful. Optimize test case: parameterization \u00b6 Let's look back to our test set quickstart-demo-rev-1.yml , and we can see the device_sn field is still hardcoded. This may be quite different from the actual scenarios. In actual scenarios, each user's device_sn is different, so we should parameterize the request parameters, which is also called parameterization . In the meanwhile, the sign field is calculated with other header fields, thus it may change significantly if any header field changes slightly. However, the test cases are only YAML documents, it is impossible to generate parameters dynamically in such text. Fortunately, we can combine Python scripts with YAML/JSON test cases in HttpRunner . To achieve this goal, we can utilize debugtalk.py plugin and variables mechanisms. To be specific, we can create a Python file ( examples/debugtalk.py ) and implement the related algorithm in it. The debugtalk.py file can not only be located beside YAML/JSON testcase file, but also can be in any upward recursive folder. Since we want debugtalk.py to be importable, we should put a __init__.py in its folder to make it as a Python module. import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" 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 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 And then, we can revise our demo test case and reference the functions. Suppose the revised file named quickstart-demo-rev-2.yml . - test : name : get token variables : - user_agent : 'iOS/10.3' - device_sn : ${gen_random_string(15)} - os_platform : 'ios' - app_version : '2.8.6' request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : $user_agent device_sn : $device_sn os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : $device_sn token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } In this revised test case, variable reference and function invoke mechanisms are both used. To make fields like device_sn can be used more than once, we bind values to variables in variables block. When we bind variables, we can not only bind exact value to a variable name, but also can call a function and bind the evaluated value to it. When we want to reference a variable in the test case, we can do this with a escape character $ . For example, $user_agent will not be taken as a normal string, and HttpRunner will consider it as a variable named user_agent , search and return its binding value. When we want to reference a function, we shall use another escape character ${} . Any content in ${} will be considered as function calling, so we should guarantee that we call functions in the right way. At the same time, variables can also be referenced as parameters of function. Optimize test case: overall config block \u00b6 There is still one issue unsolved. The device_sn field is defined in the first API test case, thus it may be impossible to reference it in other test cases. Context separation is a well-designed mechanism, and we should obey this good practice. To handle this case, overall config block is supported in HttpRunner . If we define variables or import functions in config block, these variables and functions will become global and can be referenced in the whole test set. # examples/quickstart-demo-rev-3.yml - config : name : \"smoketest for CRUD users.\" variables : - device_sn : ${gen_random_string(15)} request : base_url : http://127.0.0.1:5000 headers : device_sn : $device_sn - test : name : get token variables : - user_agent : 'iOS/10.3' - os_platform : 'ios' - app_version : '2.8.6' request : url : /api/get-token method : POST headers : user_agent : $user_agent os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : /api/users/1000 method : POST headers : token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, we define variables in config block. Also, we can set base_url in config block, thereby we can specify relative path in each API request url. Besides, we can also set common fields in config request , such as device_sn in headers. Until now, the test cases are finished and each detail is handled properly. Run test cases and generate report \u00b6 Finally, let's run test set quickstart-demo-rev-3.yml once more. $ ate examples/quickstart-demo-rev-4.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 33 ms, response_length: 46 bytes OK (0.037027)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 INFO:root: status_code: 201, response_time: 15 ms, response_length: 54 bytes OK (0.016414)s ---------------------------------------------------------------------- Ran 2 tests in 0.054s OK Generating HTML reports... Template is not specified, load default template instead. Reports generated: /Users/Leo/MyProjects/HttpRunner/reports/quickstart-demo-rev-0/2017-08-01-16-51-51.html Great! The test case runs successfully and generates a HTML test report. Further more \u00b6 This is just a starting point, see the advanced guide for the advanced features. templating data extraction and validation comparator","title":"Quick Start"},{"location":"quickstart/#quick-start","text":"First of all, remember HttpRunner is a simple yet powerful HTTP(S) testing framework. This document will help you to learn HttpRunner in 10 minutes.","title":"Quick Start"},{"location":"quickstart/#write-the-first-test-case","text":"Open your favorite text editor and you can write test cases like this. - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : F8prvGryC5beBr4g json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, each API request is described in a test block. And in the request field, it describes the detail of HTTP request, includes url, method, headers and data, which are in line with the captured traffic. You may wonder why we use the json field other than data . That's because the post data is in JSON format, when we use json to indicate the post data, we do not have to specify Content-Type to be application/json in request headers or dump data before request. Have you recalled some familiar scenes? Yes! That's what we did in requests.request ! Since HttpRunner takes full reuse of Requests , it inherits all powerful features of Requests , and we can handle HTTP request as the way we do before.","title":"Write the first test case"},{"location":"quickstart/#run-test-cases","text":"Suppose the test case file is named as quickstart-demo-rev-0.yml and is located in examples folder, then we can run it in this way. ate examples/demo-rev-0.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 48 ms, response_length: 46 bytes OK (0.049669)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 ERROR:root: Failed to POST http://127.0.0.1:5000/api/users/1000! exception msg: 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR (0.006471)s ---------------------------------------------------------------------- Ran 2 tests in 0.056s FAILED (Errors=1) Oops! The second test case failed with 403 status code. That is because we request with the same data as we captured in Charles Proxy , while the token is generated dynamically, thus the recorded data can not be be used twice directly.","title":"Run test cases"},{"location":"quickstart/#optimize-test-case-correlation","text":"To fix this problem, we should correlate token field in the second API test case, which is also called correlation . - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, the token field is no longer hardcoded, instead it is extracted from the first API request with extract mechanism. In the meanwhile, it is assigned to token variable, which can be referenced by the subsequent API requests. Now we save the test cases to quickstart-demo-rev-1.yml and rerun it, and we will find that both API requests to be successful.","title":"Optimize test case: correlation"},{"location":"quickstart/#optimize-test-case-parameterization","text":"Let's look back to our test set quickstart-demo-rev-1.yml , and we can see the device_sn field is still hardcoded. This may be quite different from the actual scenarios. In actual scenarios, each user's device_sn is different, so we should parameterize the request parameters, which is also called parameterization . In the meanwhile, the sign field is calculated with other header fields, thus it may change significantly if any header field changes slightly. However, the test cases are only YAML documents, it is impossible to generate parameters dynamically in such text. Fortunately, we can combine Python scripts with YAML/JSON test cases in HttpRunner . To achieve this goal, we can utilize debugtalk.py plugin and variables mechanisms. To be specific, we can create a Python file ( examples/debugtalk.py ) and implement the related algorithm in it. The debugtalk.py file can not only be located beside YAML/JSON testcase file, but also can be in any upward recursive folder. Since we want debugtalk.py to be importable, we should put a __init__.py in its folder to make it as a Python module. import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" 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 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 And then, we can revise our demo test case and reference the functions. Suppose the revised file named quickstart-demo-rev-2.yml . - test : name : get token variables : - user_agent : 'iOS/10.3' - device_sn : ${gen_random_string(15)} - os_platform : 'ios' - app_version : '2.8.6' request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : $user_agent device_sn : $device_sn os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : $device_sn token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } In this revised test case, variable reference and function invoke mechanisms are both used. To make fields like device_sn can be used more than once, we bind values to variables in variables block. When we bind variables, we can not only bind exact value to a variable name, but also can call a function and bind the evaluated value to it. When we want to reference a variable in the test case, we can do this with a escape character $ . For example, $user_agent will not be taken as a normal string, and HttpRunner will consider it as a variable named user_agent , search and return its binding value. When we want to reference a function, we shall use another escape character ${} . Any content in ${} will be considered as function calling, so we should guarantee that we call functions in the right way. At the same time, variables can also be referenced as parameters of function.","title":"Optimize test case: parameterization"},{"location":"quickstart/#optimize-test-case-overall-config-block","text":"There is still one issue unsolved. The device_sn field is defined in the first API test case, thus it may be impossible to reference it in other test cases. Context separation is a well-designed mechanism, and we should obey this good practice. To handle this case, overall config block is supported in HttpRunner . If we define variables or import functions in config block, these variables and functions will become global and can be referenced in the whole test set. # examples/quickstart-demo-rev-3.yml - config : name : \"smoketest for CRUD users.\" variables : - device_sn : ${gen_random_string(15)} request : base_url : http://127.0.0.1:5000 headers : device_sn : $device_sn - test : name : get token variables : - user_agent : 'iOS/10.3' - os_platform : 'ios' - app_version : '2.8.6' request : url : /api/get-token method : POST headers : user_agent : $user_agent os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : /api/users/1000 method : POST headers : token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, we define variables in config block. Also, we can set base_url in config block, thereby we can specify relative path in each API request url. Besides, we can also set common fields in config request , such as device_sn in headers. Until now, the test cases are finished and each detail is handled properly.","title":"Optimize test case: overall config block"},{"location":"quickstart/#run-test-cases-and-generate-report","text":"Finally, let's run test set quickstart-demo-rev-3.yml once more. $ ate examples/quickstart-demo-rev-4.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 33 ms, response_length: 46 bytes OK (0.037027)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 INFO:root: status_code: 201, response_time: 15 ms, response_length: 54 bytes OK (0.016414)s ---------------------------------------------------------------------- Ran 2 tests in 0.054s OK Generating HTML reports... Template is not specified, load default template instead. Reports generated: /Users/Leo/MyProjects/HttpRunner/reports/quickstart-demo-rev-0/2017-08-01-16-51-51.html Great! The test case runs successfully and generates a HTML test report.","title":"Run test cases and generate report"},{"location":"quickstart/#further-more","text":"This is just a starting point, see the advanced guide for the advanced features. templating data extraction and validation comparator","title":"Further more"},{"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\u4e1a\u754c\u9886\u5148\u7684\u6d4b\u8bd5\u5f00\u53d1\u6280\u672f\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\uff0c\u96b6\u5c5e\u4e8e\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u3002\u5b66\u9662\u8bfe\u7a0b\u5747\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 \u5f00\u6e90\u670d\u52a1\u8d5e\u52a9\u5546\uff08Open Source Sponsor\uff09 \u00b6 HttpRunner is in Sentry Sponsored plan. \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":"Sponsors"},{"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\u4e1a\u754c\u9886\u5148\u7684\u6d4b\u8bd5\u5f00\u53d1\u6280\u672f\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\uff0c\u96b6\u5c5e\u4e8e\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u3002\u5b66\u9662\u8bfe\u7a0b\u5747\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/#open-source-sponsor","text":"HttpRunner is in Sentry Sponsored plan.","title":"\u5f00\u6e90\u670d\u52a1\u8d5e\u52a9\u5546\uff08Open Source 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":"dev/models/","text":"Models \u00b6 HttpRunner v3.x uses pydantic to define models of testcase.","title":"Models"},{"location":"dev/models/#models","text":"HttpRunner v3.x uses pydantic to define models of testcase.","title":"Models"},{"location":"user/gen_tests/","text":"Record & Generate testcase \u00b6 capture HTTP request and response \u00b6 Before we write testcases, we should know the details of the API. It is a good choice to use a web debugging proxy tool like Charles Proxy to capture the HTTP traffic. For example, the image below illustrates post form data to postman-echo.com . export sessions to HAR file \u00b6 Then we can select captured request & response and export sessions to HTTP archive (.har) file. generate testcase with har2case \u00b6 When you get HAR file, you can use builtin command har2case to convert it to HttpRunner testcase. help \u00b6 $ har2case -h usage: har2case har2case [-h] [-2y] [-2j] [--filter FILTER] [--exclude EXCLUDE] [har_source_file] positional arguments: har_source_file Specify HAR source file optional arguments: -h, --help show this help message and exit -2y, --to-yml, --to-yaml Convert to YAML format, if not specified, convert to pytest format by default. -2j, --to-json Convert to JSON format, if not specified, convert to pytest format by default. --filter FILTER Specify filter keyword, only url include filter string will be converted. --exclude EXCLUDE Specify exclude keyword, url that includes exclude string will be ignored, multiple keywords can be joined with '|' generate testcase (pytest) \u00b6 Since HttpRunner 3.0.7 , har2case will convert HAR file to pytest by default, and it is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. $ har2case har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:08:01.191 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.har 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:08:01.194 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted. 2020-06-15 15:08:01.469 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py The generated pytest file is a standard Python file shown as below. # NOTE: Generated By HttpRunner v3.0.12 # FROM: har/postman-echo-post-form.har from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCasePostmanEchoPostForm ( HttpRunner ): config = Config ( \"testcase description\" ) . verify ( False ) teststeps = [ Step ( RunRequest ( \"/get\" ) . get ( \"https://postman-echo.com/get\" ) . with_params ( ** { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ) ), Step ( RunRequest ( \"/post\" ) . post ( \"https://postman-echo.com/post\" ) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . with_data ({ \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.data\" , \"\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/post\" ) ), ] if __name__ == \"__main__\" : TestCasePostmanEchoPostForm () . test_start () And it can be run with hrun command or the native pytest command. In fact, hrun is only a wrapper of pytest , thus the effect is basically the same. $ hrun har/postman_echo_post_form_test.py 2020-06-15 15:23:03.502 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:23:03.503 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... All done! \u2728 \ud83c\udf70 \u2728 1 file left unchanged. 2020-06-15 15:23:03.662 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.60s ======================================================================= $ pytest har/postman_echo_post_form_test.py ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ================================================================= 1 passed, 1 warning in 4.11s ================================================================== generate testcase (YAML/JSON) \u00b6 Of course, you can also generate former YAML/JSON testcase format. Just add -2y/--to-yml or -2j/--to-json argument to har2case . $ har2case har/postman-echo-post-form.har -2j 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:32:02.958 | INFO | httprunner.ext.har2case.utils:dump_json:122 - dump testcase to JSON format. 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.utils:dump_json:131 - Generate JSON testcase successfully: har/postman-echo-post-form.json 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: har/postman-echo-post-form.json { \"config\" : { \"name\" : \"testcase description\" , \"variables\" : {}, \"verify\" : false }, \"teststeps\" : [ { \"name\" : \"/get\" , \"request\" : { \"url\" : \"https://postman-echo.com/get\" , \"params\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }, \"method\" : \"GET\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ] } ] }, { \"name\" : \"/post\" , \"request\" : { \"url\" : \"https://postman-echo.com/post\" , \"method\" : \"POST\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"data\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.data\" , \"\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/post\" ] } ] } ] } The YAML/JSON testcase has the same info with pytest testcase, and you can run YAML/JSON testcase with hrun command. $ hrun har/postman-echo-post-form.json 2020-06-15 15:37:15.621 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:37:15.623 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.json 2020-06-15 15:37:15.625 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:37:15.625 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted, 1 file left unchanged. 2020-06-15 15:37:15.962 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.03s =======================================================================","title":"Record & Generate testcase"},{"location":"user/gen_tests/#record-generate-testcase","text":"","title":"Record & Generate testcase"},{"location":"user/gen_tests/#capture-http-request-and-response","text":"Before we write testcases, we should know the details of the API. It is a good choice to use a web debugging proxy tool like Charles Proxy to capture the HTTP traffic. For example, the image below illustrates post form data to postman-echo.com .","title":"capture HTTP request and response"},{"location":"user/gen_tests/#export-sessions-to-har-file","text":"Then we can select captured request & response and export sessions to HTTP archive (.har) file.","title":"export sessions to HAR file"},{"location":"user/gen_tests/#generate-testcase-with-har2case","text":"When you get HAR file, you can use builtin command har2case to convert it to HttpRunner testcase.","title":"generate testcase with har2case"},{"location":"user/gen_tests/#help","text":"$ har2case -h usage: har2case har2case [-h] [-2y] [-2j] [--filter FILTER] [--exclude EXCLUDE] [har_source_file] positional arguments: har_source_file Specify HAR source file optional arguments: -h, --help show this help message and exit -2y, --to-yml, --to-yaml Convert to YAML format, if not specified, convert to pytest format by default. -2j, --to-json Convert to JSON format, if not specified, convert to pytest format by default. --filter FILTER Specify filter keyword, only url include filter string will be converted. --exclude EXCLUDE Specify exclude keyword, url that includes exclude string will be ignored, multiple keywords can be joined with '|'","title":"help"},{"location":"user/gen_tests/#generate-testcase-pytest","text":"Since HttpRunner 3.0.7 , har2case will convert HAR file to pytest by default, and it is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. $ har2case har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:08:01.191 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.har 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:08:01.194 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted. 2020-06-15 15:08:01.469 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py The generated pytest file is a standard Python file shown as below. # NOTE: Generated By HttpRunner v3.0.12 # FROM: har/postman-echo-post-form.har from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCasePostmanEchoPostForm ( HttpRunner ): config = Config ( \"testcase description\" ) . verify ( False ) teststeps = [ Step ( RunRequest ( \"/get\" ) . get ( \"https://postman-echo.com/get\" ) . with_params ( ** { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ) ), Step ( RunRequest ( \"/post\" ) . post ( \"https://postman-echo.com/post\" ) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . with_data ({ \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.data\" , \"\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/post\" ) ), ] if __name__ == \"__main__\" : TestCasePostmanEchoPostForm () . test_start () And it can be run with hrun command or the native pytest command. In fact, hrun is only a wrapper of pytest , thus the effect is basically the same. $ hrun har/postman_echo_post_form_test.py 2020-06-15 15:23:03.502 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:23:03.503 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... All done! \u2728 \ud83c\udf70 \u2728 1 file left unchanged. 2020-06-15 15:23:03.662 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.60s ======================================================================= $ pytest har/postman_echo_post_form_test.py ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ================================================================= 1 passed, 1 warning in 4.11s ==================================================================","title":"generate testcase (pytest)"},{"location":"user/gen_tests/#generate-testcase-yamljson","text":"Of course, you can also generate former YAML/JSON testcase format. Just add -2y/--to-yml or -2j/--to-json argument to har2case . $ har2case har/postman-echo-post-form.har -2j 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:32:02.958 | INFO | httprunner.ext.har2case.utils:dump_json:122 - dump testcase to JSON format. 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.utils:dump_json:131 - Generate JSON testcase successfully: har/postman-echo-post-form.json 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: har/postman-echo-post-form.json { \"config\" : { \"name\" : \"testcase description\" , \"variables\" : {}, \"verify\" : false }, \"teststeps\" : [ { \"name\" : \"/get\" , \"request\" : { \"url\" : \"https://postman-echo.com/get\" , \"params\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }, \"method\" : \"GET\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ] } ] }, { \"name\" : \"/post\" , \"request\" : { \"url\" : \"https://postman-echo.com/post\" , \"method\" : \"POST\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"data\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.data\" , \"\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/post\" ] } ] } ] } The YAML/JSON testcase has the same info with pytest testcase, and you can run YAML/JSON testcase with hrun command. $ hrun har/postman-echo-post-form.json 2020-06-15 15:37:15.621 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:37:15.623 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.json 2020-06-15 15:37:15.625 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:37:15.625 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted, 1 file left unchanged. 2020-06-15 15:37:15.962 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.03s =======================================================================","title":"generate testcase (YAML/JSON)"},{"location":"user/scaffold/","text":"Scaffold \u00b6 If you want to create a new project, you can use the scaffold to startup quickly. help \u00b6 $ httprunner startproject -h usage: httprunner startproject [-h] [project_name] positional arguments: project_name Specify new project name. optional arguments: -h, --help show this help message and exit create new project \u00b6 The only argument you need to specify is the project name. $ httprunner startproject demo 2020-06-15 11:53:25.498 | INFO | httprunner.scaffold:create_scaffold:37 - Create new project: demo Project Root Dir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo created folder: demo created folder: demo/har created folder: demo/testcases created folder: demo/reports created file: demo/testcases/demo_testcase_request.yml created file: demo/testcases/demo_testcase_ref.yml created file: demo/debugtalk.py created file: demo/.env created file: demo/.gitignore $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files If you specify a project name that already exists, you will get a warning. $ httprunner startproject demo 2020-06-15 11:55:03.192 | WARNING | httprunner.scaffold:create_scaffold:32 - Project demo exists, please specify a new project name. $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files run scaffold project \u00b6 The scaffold project has several valid testcases, so you can run tests without any edit. $ hrun demo 2020-06-15 11:57:15.883 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/.env 2020-06-15 11:57:15.883 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 11:57:15.884 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 11:57:15.885 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref.yml 2020-06-15 11:57:15.898 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.899 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py 2020-06-15 11:57:15.900 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py 2020-06-15 11:57:15.911 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.912 | INFO | httprunner.make:__ensure_project_meta_files:128 - copy .env to /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/_env 2020-06-15 11:57:15.912 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py All done! \u2728 \ud83c\udf70 \u2728 2 files reformatted, 1 file left unchanged. 2020-06-15 11:57:16.299 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 2 items demo/testcases/demo_testcase_request_test.py . [ 50%] demo/testcases/demo_testcase_ref_test.py . [100%] ======================================================================= 2 passed in 6.87s =======================================================================","title":"Scaffold"},{"location":"user/scaffold/#scaffold","text":"If you want to create a new project, you can use the scaffold to startup quickly.","title":"Scaffold"},{"location":"user/scaffold/#help","text":"$ httprunner startproject -h usage: httprunner startproject [-h] [project_name] positional arguments: project_name Specify new project name. optional arguments: -h, --help show this help message and exit","title":"help"},{"location":"user/scaffold/#create-new-project","text":"The only argument you need to specify is the project name. $ httprunner startproject demo 2020-06-15 11:53:25.498 | INFO | httprunner.scaffold:create_scaffold:37 - Create new project: demo Project Root Dir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo created folder: demo created folder: demo/har created folder: demo/testcases created folder: demo/reports created file: demo/testcases/demo_testcase_request.yml created file: demo/testcases/demo_testcase_ref.yml created file: demo/debugtalk.py created file: demo/.env created file: demo/.gitignore $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files If you specify a project name that already exists, you will get a warning. $ httprunner startproject demo 2020-06-15 11:55:03.192 | WARNING | httprunner.scaffold:create_scaffold:32 - Project demo exists, please specify a new project name. $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files","title":"create new project"},{"location":"user/scaffold/#run-scaffold-project","text":"The scaffold project has several valid testcases, so you can run tests without any edit. $ hrun demo 2020-06-15 11:57:15.883 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/.env 2020-06-15 11:57:15.883 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 11:57:15.884 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 11:57:15.885 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref.yml 2020-06-15 11:57:15.898 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.899 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py 2020-06-15 11:57:15.900 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py 2020-06-15 11:57:15.911 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.912 | INFO | httprunner.make:__ensure_project_meta_files:128 - copy .env to /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/_env 2020-06-15 11:57:15.912 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py All done! \u2728 \ud83c\udf70 \u2728 2 files reformatted, 1 file left unchanged. 2020-06-15 11:57:16.299 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 2 items demo/testcases/demo_testcase_request_test.py . [ 50%] demo/testcases/demo_testcase_ref_test.py . [100%] ======================================================================= 2 passed in 6.87s =======================================================================","title":"run scaffold project"},{"location":"user/write_testcase/","text":"Write Testcase \u00b6 HttpRunner v3.x supports three testcase formats, pytest , YAML and JSON . It is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. record & generate testcase \u00b6 If the SUT (system under test) is ready, the most efficient way is to capture HTTP traffic first and then generate testcases with HAR file. Refer to Record & Generate testcase for more details. Based on the generated pytest testcase, you can then do some adjustment as needed, thus you need to know the details of testcase format. testcase structure \u00b6 Each testcase is a subclass of HttpRunner , and must have two class attributes: config and teststeps . config: configure testcase level settings, including base_url , verify , variables , export . teststeps: list of teststep ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Besides, variables / extract / validate / hooks mechanisms are supported to create extremely complex test scenarios. from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCaseRequestWithFunctions ( HttpRunner ): config = ( Config ( \"request methods testcase with functions\" ) . variables ( ** { \"foo1\" : \"config_bar1\" , \"foo2\" : \"config_bar2\" , \"expect_foo1\" : \"config_bar1\" , \"expect_foo2\" : \"config_bar2\" , } ) . base_url ( \"https://postman-echo.com\" ) . verify ( False ) . export ( * [ \"foo3\" ]) ) teststeps = [ Step ( RunRequest ( \"get with params\" ) . with_variables ( ** { \"foo1\" : \"bar11\" , \"foo2\" : \"bar21\" , \"sum_v\" : \"${sum_two(1, 2)}\" } ) . get ( \"/get\" ) . with_params ( ** { \"foo1\" : \"$foo1\" , \"foo2\" : \"$foo2\" , \"sum_v\" : \"$sum_v\" }) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" }) . extract () . with_jmespath ( \"body.args.foo2\" , \"foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.args.foo1\" , \"bar11\" ) . assert_equal ( \"body.args.sum_v\" , \"3\" ) . assert_equal ( \"body.args.foo2\" , \"bar21\" ) ), Step ( RunRequest ( \"post form data\" ) . with_variables ( ** { \"foo2\" : \"bar23\" }) . post ( \"/post\" ) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , } ) . with_data ( \"foo1=$foo1&foo2=$foo2&foo3=$foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.form.foo1\" , \"$expect_foo1\" ) . assert_equal ( \"body.form.foo2\" , \"bar23\" ) . assert_equal ( \"body.form.foo3\" , \"bar21\" ) ), ] if __name__ == \"__main__\" : TestCaseRequestWithFunctions () . test_start () chain call \u00b6 One of the most awesome features of HttpRunner v3.x is chain call , with which you do not need to remember any testcase format details and you can get intelligent completion when you write testcases in IDE. config \u00b6 Each testcase should have one config part, in which you can configure testcase level settings. name (required) \u00b6 Specify testcase name. This will be displayed in execution log and test report. base_url (optional) \u00b6 Specify common schema and host part of the SUT, e.g. https://postman-echo.com . If base_url is specified, url in teststep can only set relative path part. This is especially useful if you want to switch between different SUT environments. variables (optional) \u00b6 Specify common variables of testcase. Each teststep can reference config variable which is not set in step variables. In other words, step variables have higher priority than config variables. verify (optional) \u00b6 Specify whether to verify the server\u2019s TLS certificate. This is especially useful if we want to record HTTP traffic of testcase execution, because SSLError will be occurred if verify is not set or been set to True. SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1076)')) export (optional) \u00b6 Specify the exported session variables of testcase. Consider each testcase as a black box, config variables is the input part, and config export is the output part. In particular, when a testcase is referenced in another testcase's step, and will be extracted some session variables to be used in subsequent teststeps, then the extracted session variables should be configured in config export part. teststeps \u00b6 Each testcase should have one or multiple ordered test steps ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Notice: The concept of API in HttpRunner v2.x has been deprecated for simplification. You can consider API as a testcase that has only one request step. RunRequest(name) \u00b6 RunRequest is used in a step to make request to API and do some extraction or validations for response. The argument name of RunRequest is used to specify teststep name, which will be displayed in execution log and test report. .with_variables \u00b6 Specify teststep variables. The variables of each step are independent, thus if you want to share variables in multiple steps, you should define variables in config variables. Besides, the step variables will override the ones that have the same name in config variables. .method(url) \u00b6 Specify HTTP method and the url of SUT. These are corresponding to method and url arguments of requests.request . If base_url is set in config, url can only set relative path part. .with_params \u00b6 Specify query string for the request url. This is corresponding to the params argument of requests.request . .with_headers \u00b6 Specify HTTP headers for the request. This is corresponding to the headers argument of requests.request . .with_cookies \u00b6 Specify HTTP request cookies. This is corresponding to the cookies argument of requests.request . .with_data \u00b6 Specify HTTP request body. This is corresponding to the data argument of requests.request . .with_json \u00b6 Specify HTTP request body in json. This is corresponding to the json argument of requests.request . extract \u00b6 .with_jmespath \u00b6 Extract JSON response body with jmespath . with_jmespath(jmes_path: Text, var_name: Text) jmes_path: jmespath expression var_name: the variable name that stores extracted value validate \u00b6 RunTestCase(name) \u00b6 .with_variables \u00b6 Besides, variables / extract / validate / hooks mechanisms are supported to create extremely complex test scenarios.","title":"Write Testcase"},{"location":"user/write_testcase/#write-testcase","text":"HttpRunner v3.x supports three testcase formats, pytest , YAML and JSON . It is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format.","title":"Write Testcase"},{"location":"user/write_testcase/#record-generate-testcase","text":"If the SUT (system under test) is ready, the most efficient way is to capture HTTP traffic first and then generate testcases with HAR file. Refer to Record & Generate testcase for more details. Based on the generated pytest testcase, you can then do some adjustment as needed, thus you need to know the details of testcase format.","title":"record & generate testcase"},{"location":"user/write_testcase/#testcase-structure","text":"Each testcase is a subclass of HttpRunner , and must have two class attributes: config and teststeps . config: configure testcase level settings, including base_url , verify , variables , export . teststeps: list of teststep ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Besides, variables / extract / validate / hooks mechanisms are supported to create extremely complex test scenarios. from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCaseRequestWithFunctions ( HttpRunner ): config = ( Config ( \"request methods testcase with functions\" ) . variables ( ** { \"foo1\" : \"config_bar1\" , \"foo2\" : \"config_bar2\" , \"expect_foo1\" : \"config_bar1\" , \"expect_foo2\" : \"config_bar2\" , } ) . base_url ( \"https://postman-echo.com\" ) . verify ( False ) . export ( * [ \"foo3\" ]) ) teststeps = [ Step ( RunRequest ( \"get with params\" ) . with_variables ( ** { \"foo1\" : \"bar11\" , \"foo2\" : \"bar21\" , \"sum_v\" : \"${sum_two(1, 2)}\" } ) . get ( \"/get\" ) . with_params ( ** { \"foo1\" : \"$foo1\" , \"foo2\" : \"$foo2\" , \"sum_v\" : \"$sum_v\" }) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" }) . extract () . with_jmespath ( \"body.args.foo2\" , \"foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.args.foo1\" , \"bar11\" ) . assert_equal ( \"body.args.sum_v\" , \"3\" ) . assert_equal ( \"body.args.foo2\" , \"bar21\" ) ), Step ( RunRequest ( \"post form data\" ) . with_variables ( ** { \"foo2\" : \"bar23\" }) . post ( \"/post\" ) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , } ) . with_data ( \"foo1=$foo1&foo2=$foo2&foo3=$foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.form.foo1\" , \"$expect_foo1\" ) . assert_equal ( \"body.form.foo2\" , \"bar23\" ) . assert_equal ( \"body.form.foo3\" , \"bar21\" ) ), ] if __name__ == \"__main__\" : TestCaseRequestWithFunctions () . test_start ()","title":"testcase structure"},{"location":"user/write_testcase/#chain-call","text":"One of the most awesome features of HttpRunner v3.x is chain call , with which you do not need to remember any testcase format details and you can get intelligent completion when you write testcases in IDE.","title":"chain call"},{"location":"user/write_testcase/#config","text":"Each testcase should have one config part, in which you can configure testcase level settings.","title":"config"},{"location":"user/write_testcase/#name-required","text":"Specify testcase name. This will be displayed in execution log and test report.","title":"name (required)"},{"location":"user/write_testcase/#base_url-optional","text":"Specify common schema and host part of the SUT, e.g. https://postman-echo.com . If base_url is specified, url in teststep can only set relative path part. This is especially useful if you want to switch between different SUT environments.","title":"base_url (optional)"},{"location":"user/write_testcase/#variables-optional","text":"Specify common variables of testcase. Each teststep can reference config variable which is not set in step variables. In other words, step variables have higher priority than config variables.","title":"variables (optional)"},{"location":"user/write_testcase/#verify-optional","text":"Specify whether to verify the server\u2019s TLS certificate. This is especially useful if we want to record HTTP traffic of testcase execution, because SSLError will be occurred if verify is not set or been set to True. SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1076)'))","title":"verify (optional)"},{"location":"user/write_testcase/#export-optional","text":"Specify the exported session variables of testcase. Consider each testcase as a black box, config variables is the input part, and config export is the output part. In particular, when a testcase is referenced in another testcase's step, and will be extracted some session variables to be used in subsequent teststeps, then the extracted session variables should be configured in config export part.","title":"export (optional)"},{"location":"user/write_testcase/#teststeps","text":"Each testcase should have one or multiple ordered test steps ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Notice: The concept of API in HttpRunner v2.x has been deprecated for simplification. You can consider API as a testcase that has only one request step.","title":"teststeps"},{"location":"user/write_testcase/#runrequestname","text":"RunRequest is used in a step to make request to API and do some extraction or validations for response. The argument name of RunRequest is used to specify teststep name, which will be displayed in execution log and test report.","title":"RunRequest(name)"},{"location":"user/write_testcase/#with_variables","text":"Specify teststep variables. The variables of each step are independent, thus if you want to share variables in multiple steps, you should define variables in config variables. Besides, the step variables will override the ones that have the same name in config variables.","title":".with_variables"},{"location":"user/write_testcase/#methodurl","text":"Specify HTTP method and the url of SUT. These are corresponding to method and url arguments of requests.request . If base_url is set in config, url can only set relative path part.","title":".method(url)"},{"location":"user/write_testcase/#with_params","text":"Specify query string for the request url. This is corresponding to the params argument of requests.request .","title":".with_params"},{"location":"user/write_testcase/#with_headers","text":"Specify HTTP headers for the request. This is corresponding to the headers argument of requests.request .","title":".with_headers"},{"location":"user/write_testcase/#with_cookies","text":"Specify HTTP request cookies. This is corresponding to the cookies argument of requests.request .","title":".with_cookies"},{"location":"user/write_testcase/#with_data","text":"Specify HTTP request body. This is corresponding to the data argument of requests.request .","title":".with_data"},{"location":"user/write_testcase/#with_json","text":"Specify HTTP request body in json. This is corresponding to the json argument of requests.request .","title":".with_json"},{"location":"user/write_testcase/#extract","text":"","title":"extract"},{"location":"user/write_testcase/#with_jmespath","text":"Extract JSON response body with jmespath . with_jmespath(jmes_path: Text, var_name: Text) jmes_path: jmespath expression var_name: the variable name that stores extracted value","title":".with_jmespath"},{"location":"user/write_testcase/#validate","text":"","title":"validate"},{"location":"user/write_testcase/#runtestcasename","text":"","title":"RunTestCase(name)"},{"location":"user/write_testcase/#with_variables_1","text":"Besides, variables / extract / validate / hooks mechanisms are supported to create extremely complex test scenarios.","title":".with_variables"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"HttpRunner \u00b6 HttpRunner is a simple & elegant, yet powerful HTTP(S) testing framework. Enjoy! \u2728 \ud83d\ude80 \u2728 This docs site is corresponding to the latest version 3.x , for 2.x you can reference archive link . Design Philosophy \u00b6 Convention over configuration ROI matters Embrace open source, leverage requests , pytest , pydantic , allure and locust . Key Features \u00b6 Inherit all powerful features of requests , just have fun to handle HTTP(S) in human way. Define testcase in YAML or JSON format, run with pytest in concise and elegant manner. Record and generate testcases with HAR support. Supports variables / extract / validate / hooks mechanisms to create extremely complex test scenarios. With debugtalk.py plugin, any function can be used in any part of your testcase. With jmespath , extract and validate json response has never been easier. With pytest , hundreds of plugins are readily available. With allure , test report can be pretty nice and powerful. With reuse of locust , you can run performance test without extra work. CLI command supported, perfect combination with CI/CD . Subscribe \u00b6 \u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"Introduction"},{"location":"#httprunner","text":"HttpRunner is a simple & elegant, yet powerful HTTP(S) testing framework. Enjoy! \u2728 \ud83d\ude80 \u2728 This docs site is corresponding to the latest version 3.x , for 2.x you can reference archive link .","title":"HttpRunner"},{"location":"#design-philosophy","text":"Convention over configuration ROI matters Embrace open source, leverage requests , pytest , pydantic , allure and locust .","title":"Design Philosophy"},{"location":"#key-features","text":"Inherit all powerful features of requests , just have fun to handle HTTP(S) in human way. Define testcase in YAML or JSON format, run with pytest in concise and elegant manner. Record and generate testcases with HAR support. Supports variables / extract / validate / hooks mechanisms to create extremely complex test scenarios. With debugtalk.py plugin, any function can be used in any part of your testcase. With jmespath , extract and validate json response has never been easier. With pytest , hundreds of plugins are readily available. With allure , test report can be pretty nice and powerful. With reuse of locust , you can run performance test without extra work. CLI command supported, perfect combination with CI/CD .","title":"Key Features"},{"location":"#subscribe","text":"\u5173\u6ce8 HttpRunner \u7684\u5fae\u4fe1\u516c\u4f17\u53f7\uff0c\u7b2c\u4e00\u65f6\u95f4\u83b7\u5f97\u6700\u65b0\u8d44\u8baf\u3002","title":"Subscribe"},{"location":"CHANGELOG/","text":"Release History \u00b6 3.0.13 (2020-06-15) \u00b6 Fixed fix: avoid '.csv' been converted to '_csv' fix: convert har to JSON format testcase fix: missing ${var} handling in overriding config variables fix: SyntaxError caused by quote in case of headers.\"Set-Cookie\" fix: FileExistsError when specified project name conflicts with existed file fix: testcase path handling error when path startswith \"./\" or \".\\\" 3.0.12 (2020-06-14) \u00b6 Fixed fix: compatibility with different path separators of Linux and Windows fix: IndexError in ensure_file_path_valid when file_path=os.getcwd() fix: ensure step referenced api, convert to v3 testcase fix: several other compatibility issues Changed change: skip reporting sentry for errors occurred in debugtalk.py 3.0.11 (2020-06-08) \u00b6 Changed change: override variables (1) testcase: session variables > step variables > config variables (2) testsuite: testcase variables > config variables (3) testsuite testcase variables > testcase config variables Fixed fix: incorrect summary success when testcase failed fix: reload to refresh previously loaded debugtalk module fix: escape $$ in variable value 3.0.10 (2020-06-07) \u00b6 Added feat: implement step setup/teardown hooks feat: support alter response in teardown hooks Fixed fix: ensure upload ready fix: add ExtendJSONEncoder to safely dump json data with python object, such as MultipartEncoder 3.0.9 (2020-06-07) \u00b6 Fixed fix: miss formatting referenced testcase fix: handle cases when parent directory name includes dot/hyphen/space Changed change: add export keyword in TStep to export session variables from referenced testcase change: rename TestCaseInOut field, config_vars and export_vars change: rename StepData field, export_vars change: add --tb=short for hrun command to use shorter traceback format by default change: search debugtalk.py upward recursively until system root dir 3.0.8 (2020-06-04) \u00b6 Added feat: add sentry sdk feat: extract session variable from referenced testcase step Fixed fix: missing request json fix: override testsuite/testcase config verify fix: only strip whitespaces and tabs, \\n\\r are left because they maybe used in changeset fix: log testcase duration before raise ValidationFailure Changed change: add httprunner version in generated pytest file 3.0.7 (2020-06-03) \u00b6 Added feat: make pytest files in chain style feat: hrun supports run pytest files feat: get raw testcase model from pytest file Fixed fix: convert jmespath.search result to int/float unintentionally fix: referenced testcase should not be run duplicately fix: requests.cookies.CookieConflictError, multiple cookies with name fix: missing exit code from pytest fix: skip invalid testcase/testsuite yaml/json file Changed change: har2case generate pytest file by default docs: update sponsor info 3.0.6 (2020-05-29) \u00b6 Added feat: make referenced testcase as pytest class Fixed fix: ensure converted python file in utf-8 encoding fix: duplicate running referenced testcase fix: ensure compatibility issues between testcase format v2 and v3 fix: ensure compatibility with deprecated cli args in v2, include --failfast/--report-file/--save-tests fix: UnicodeDecodeError when request body in protobuf Changed change: make allure-pytest , requests-toolbelt , filetype as optional dependencies change: move all unittests to tests folder change: save testcase log in PWD/logs/ directory 3.0.5 (2020-05-22) \u00b6 Added feat: each testcase has an unique id in uuid4 format feat: add default header HRUN-Request-ID for each testcase #721 feat: builtin allure report feat: dump log for each testcase Fixed fix: ensure referenced testcase share the same session Changed change: remove default added -s option for hrun 3.0.4 (2020-05-19) \u00b6 Added feat: make testsuite and run testsuite feat: testcase/testsuite config support getting variables by function feat: har2case with request cookies feat: log request/response headers and body with indent Fixed fix: extract response cookies fix: handle errors when no valid testcases generated Changed change: har2case do not ignore request headers, except for header startswith : 3.0.3 (2020-05-17) \u00b6 Fixed fix: compatibility with testcase file path includes dots, space and minus sign fix: testcase generator, validate content.xxx => body.xxx fix: scaffold for v3 3.0.2 (2020-05-16) \u00b6 Added feat: add make sub-command to generate python testcases from YAML/JSON feat: format generated python testcases with black test: add postman echo & httpbin as testcase examples Changed refactor all replace jsonschema validation with pydantic remove compatibility with testcase/testsuite format v1 replace unittest with pytest remove builtin html report, allure will be used with pytest later remove locust support temporarily update command line interface 3.0.1 (2020-03-24) \u00b6 Changed remove sentry sdk 3.0.0 (2020-03-10) \u00b6 Added feat: dump log for each testcase feat: add default header HRUN-Request-ID for each testcase #721 Changed remove support for Python 2.7 replace logging with loguru replace string format with f-string remove dependency colorama and colorlog generate reports/logs folder in current working directory remove cli --validate remove cli --pretty","title":"CHANGELOG"},{"location":"CHANGELOG/#release-history","text":"","title":"Release History"},{"location":"CHANGELOG/#3013-2020-06-15","text":"Fixed fix: avoid '.csv' been converted to '_csv' fix: convert har to JSON format testcase fix: missing ${var} handling in overriding config variables fix: SyntaxError caused by quote in case of headers.\"Set-Cookie\" fix: FileExistsError when specified project name conflicts with existed file fix: testcase path handling error when path startswith \"./\" or \".\\\"","title":"3.0.13 (2020-06-15)"},{"location":"CHANGELOG/#3012-2020-06-14","text":"Fixed fix: compatibility with different path separators of Linux and Windows fix: IndexError in ensure_file_path_valid when file_path=os.getcwd() fix: ensure step referenced api, convert to v3 testcase fix: several other compatibility issues Changed change: skip reporting sentry for errors occurred in debugtalk.py","title":"3.0.12 (2020-06-14)"},{"location":"CHANGELOG/#3011-2020-06-08","text":"Changed change: override variables (1) testcase: session variables > step variables > config variables (2) testsuite: testcase variables > config variables (3) testsuite testcase variables > testcase config variables Fixed fix: incorrect summary success when testcase failed fix: reload to refresh previously loaded debugtalk module fix: escape $$ in variable value","title":"3.0.11 (2020-06-08)"},{"location":"CHANGELOG/#3010-2020-06-07","text":"Added feat: implement step setup/teardown hooks feat: support alter response in teardown hooks Fixed fix: ensure upload ready fix: add ExtendJSONEncoder to safely dump json data with python object, such as MultipartEncoder","title":"3.0.10 (2020-06-07)"},{"location":"CHANGELOG/#309-2020-06-07","text":"Fixed fix: miss formatting referenced testcase fix: handle cases when parent directory name includes dot/hyphen/space Changed change: add export keyword in TStep to export session variables from referenced testcase change: rename TestCaseInOut field, config_vars and export_vars change: rename StepData field, export_vars change: add --tb=short for hrun command to use shorter traceback format by default change: search debugtalk.py upward recursively until system root dir","title":"3.0.9 (2020-06-07)"},{"location":"CHANGELOG/#308-2020-06-04","text":"Added feat: add sentry sdk feat: extract session variable from referenced testcase step Fixed fix: missing request json fix: override testsuite/testcase config verify fix: only strip whitespaces and tabs, \\n\\r are left because they maybe used in changeset fix: log testcase duration before raise ValidationFailure Changed change: add httprunner version in generated pytest file","title":"3.0.8 (2020-06-04)"},{"location":"CHANGELOG/#307-2020-06-03","text":"Added feat: make pytest files in chain style feat: hrun supports run pytest files feat: get raw testcase model from pytest file Fixed fix: convert jmespath.search result to int/float unintentionally fix: referenced testcase should not be run duplicately fix: requests.cookies.CookieConflictError, multiple cookies with name fix: missing exit code from pytest fix: skip invalid testcase/testsuite yaml/json file Changed change: har2case generate pytest file by default docs: update sponsor info","title":"3.0.7 (2020-06-03)"},{"location":"CHANGELOG/#306-2020-05-29","text":"Added feat: make referenced testcase as pytest class Fixed fix: ensure converted python file in utf-8 encoding fix: duplicate running referenced testcase fix: ensure compatibility issues between testcase format v2 and v3 fix: ensure compatibility with deprecated cli args in v2, include --failfast/--report-file/--save-tests fix: UnicodeDecodeError when request body in protobuf Changed change: make allure-pytest , requests-toolbelt , filetype as optional dependencies change: move all unittests to tests folder change: save testcase log in PWD/logs/ directory","title":"3.0.6 (2020-05-29)"},{"location":"CHANGELOG/#305-2020-05-22","text":"Added feat: each testcase has an unique id in uuid4 format feat: add default header HRUN-Request-ID for each testcase #721 feat: builtin allure report feat: dump log for each testcase Fixed fix: ensure referenced testcase share the same session Changed change: remove default added -s option for hrun","title":"3.0.5 (2020-05-22)"},{"location":"CHANGELOG/#304-2020-05-19","text":"Added feat: make testsuite and run testsuite feat: testcase/testsuite config support getting variables by function feat: har2case with request cookies feat: log request/response headers and body with indent Fixed fix: extract response cookies fix: handle errors when no valid testcases generated Changed change: har2case do not ignore request headers, except for header startswith :","title":"3.0.4 (2020-05-19)"},{"location":"CHANGELOG/#303-2020-05-17","text":"Fixed fix: compatibility with testcase file path includes dots, space and minus sign fix: testcase generator, validate content.xxx => body.xxx fix: scaffold for v3","title":"3.0.3 (2020-05-17)"},{"location":"CHANGELOG/#302-2020-05-16","text":"Added feat: add make sub-command to generate python testcases from YAML/JSON feat: format generated python testcases with black test: add postman echo & httpbin as testcase examples Changed refactor all replace jsonschema validation with pydantic remove compatibility with testcase/testsuite format v1 replace unittest with pytest remove builtin html report, allure will be used with pytest later remove locust support temporarily update command line interface","title":"3.0.2 (2020-05-16)"},{"location":"CHANGELOG/#301-2020-03-24","text":"Changed remove sentry sdk","title":"3.0.1 (2020-03-24)"},{"location":"CHANGELOG/#300-2020-03-10","text":"Added feat: dump log for each testcase feat: add default header HRUN-Request-ID for each testcase #721 Changed remove support for Python 2.7 replace logging with loguru replace string format with f-string remove dependency colorama and colorlog generate reports/logs folder in current working directory remove cli --validate remove cli --pretty","title":"3.0.0 (2020-03-10)"},{"location":"installation/","text":"HttpRunner is developed with Python, it supports Python 3.6+ and most operating systems. Combination of Python 3.6/3.7/3.8 and macOS/Linux/Windows are tested continuously on GitHub-Actions . Installation \u00b6 HttpRunner is available on PyPI and can be installed through pip . $ pip3 install httprunner If you want to keep up with the latest version, you can install with github repository url. $ pip3 install git+https://github.com/httprunner/httprunner.git@master If\b you have installed HttpRunner before and want to upgrade to the latest version, you can use the -U option. $ pip3 install -U httprunner $ pip3 install -U git+https://github.com/httprunner/httprunner.git@master Check Installation \u00b6 When HttpRunner is installed, 4 commands will be added in your system. httprunner : main command, used for all functions hrun : alias for httprunner run , used to run YAML/JSON/pytest testcases hmake : alias for httprunner make , used to convert YAML/JSON testcases to pytest files har2case : alias for httprunner har2case , used to convert HAR to YAML/JSON testcases To see HttpRunner version: $ httprunner -V # hrun -V 3.0.10 To see available options, run: $ httprunner -h usage: httprunner [-h] [-V] {run,startproject,har2case,make} ... One-stop solution for HTTP(S) testing. positional arguments: {run,startproject,har2case,make} sub-command help run Make HttpRunner testcases and run with pytest. startproject Create a new project with template structure. har2case Convert HAR(HTTP Archive) to YAML/JSON testcases for HttpRunner. make Convert YAML/JSON testcases to pytest cases. optional arguments: -h, --help show this help message and exit -V, --version show version","title":"Installation"},{"location":"installation/#installation","text":"HttpRunner is available on PyPI and can be installed through pip . $ pip3 install httprunner If you want to keep up with the latest version, you can install with github repository url. $ pip3 install git+https://github.com/httprunner/httprunner.git@master If\b you have installed HttpRunner before and want to upgrade to the latest version, you can use the -U option. $ pip3 install -U httprunner $ pip3 install -U git+https://github.com/httprunner/httprunner.git@master","title":"Installation"},{"location":"installation/#check-installation","text":"When HttpRunner is installed, 4 commands will be added in your system. httprunner : main command, used for all functions hrun : alias for httprunner run , used to run YAML/JSON/pytest testcases hmake : alias for httprunner make , used to convert YAML/JSON testcases to pytest files har2case : alias for httprunner har2case , used to convert HAR to YAML/JSON testcases To see HttpRunner version: $ httprunner -V # hrun -V 3.0.10 To see available options, run: $ httprunner -h usage: httprunner [-h] [-V] {run,startproject,har2case,make} ... One-stop solution for HTTP(S) testing. positional arguments: {run,startproject,har2case,make} sub-command help run Make HttpRunner testcases and run with pytest. startproject Create a new project with template structure. har2case Convert HAR(HTTP Archive) to YAML/JSON testcases for HttpRunner. make Convert YAML/JSON testcases to pytest cases. optional arguments: -h, --help show this help message and exit -V, --version show version","title":"Check Installation"},{"location":"quickstart/","text":"Quick Start \u00b6 First of all, remember HttpRunner is a simple yet powerful HTTP(S) testing framework. This document will help you to learn HttpRunner in 10 minutes. Write the first test case \u00b6 Open your favorite text editor and you can write test cases like this. - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : F8prvGryC5beBr4g json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, each API request is described in a test block. And in the request field, it describes the detail of HTTP request, includes url, method, headers and data, which are in line with the captured traffic. You may wonder why we use the json field other than data . That's because the post data is in JSON format, when we use json to indicate the post data, we do not have to specify Content-Type to be application/json in request headers or dump data before request. Have you recalled some familiar scenes? Yes! That's what we did in requests.request ! Since HttpRunner takes full reuse of Requests , it inherits all powerful features of Requests , and we can handle HTTP request as the way we do before. Run test cases \u00b6 Suppose the test case file is named as quickstart-demo-rev-0.yml and is located in examples folder, then we can run it in this way. ate examples/demo-rev-0.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 48 ms, response_length: 46 bytes OK (0.049669)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 ERROR:root: Failed to POST http://127.0.0.1:5000/api/users/1000! exception msg: 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR (0.006471)s ---------------------------------------------------------------------- Ran 2 tests in 0.056s FAILED (Errors=1) Oops! The second test case failed with 403 status code. That is because we request with the same data as we captured in Charles Proxy , while the token is generated dynamically, thus the recorded data can not be be used twice directly. Optimize test case: correlation \u00b6 To fix this problem, we should correlate token field in the second API test case, which is also called correlation . - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, the token field is no longer hardcoded, instead it is extracted from the first API request with extract mechanism. In the meanwhile, it is assigned to token variable, which can be referenced by the subsequent API requests. Now we save the test cases to quickstart-demo-rev-1.yml and rerun it, and we will find that both API requests to be successful. Optimize test case: parameterization \u00b6 Let's look back to our test set quickstart-demo-rev-1.yml , and we can see the device_sn field is still hardcoded. This may be quite different from the actual scenarios. In actual scenarios, each user's device_sn is different, so we should parameterize the request parameters, which is also called parameterization . In the meanwhile, the sign field is calculated with other header fields, thus it may change significantly if any header field changes slightly. However, the test cases are only YAML documents, it is impossible to generate parameters dynamically in such text. Fortunately, we can combine Python scripts with YAML/JSON test cases in HttpRunner . To achieve this goal, we can utilize debugtalk.py plugin and variables mechanisms. To be specific, we can create a Python file ( examples/debugtalk.py ) and implement the related algorithm in it. The debugtalk.py file can not only be located beside YAML/JSON testcase file, but also can be in any upward recursive folder. Since we want debugtalk.py to be importable, we should put a __init__.py in its folder to make it as a Python module. import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" 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 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 And then, we can revise our demo test case and reference the functions. Suppose the revised file named quickstart-demo-rev-2.yml . - test : name : get token variables : - user_agent : 'iOS/10.3' - device_sn : ${gen_random_string(15)} - os_platform : 'ios' - app_version : '2.8.6' request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : $user_agent device_sn : $device_sn os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : $device_sn token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } In this revised test case, variable reference and function invoke mechanisms are both used. To make fields like device_sn can be used more than once, we bind values to variables in variables block. When we bind variables, we can not only bind exact value to a variable name, but also can call a function and bind the evaluated value to it. When we want to reference a variable in the test case, we can do this with a escape character $ . For example, $user_agent will not be taken as a normal string, and HttpRunner will consider it as a variable named user_agent , search and return its binding value. When we want to reference a function, we shall use another escape character ${} . Any content in ${} will be considered as function calling, so we should guarantee that we call functions in the right way. At the same time, variables can also be referenced as parameters of function. Optimize test case: overall config block \u00b6 There is still one issue unsolved. The device_sn field is defined in the first API test case, thus it may be impossible to reference it in other test cases. Context separation is a well-designed mechanism, and we should obey this good practice. To handle this case, overall config block is supported in HttpRunner . If we define variables or import functions in config block, these variables and functions will become global and can be referenced in the whole test set. # examples/quickstart-demo-rev-3.yml - config : name : \"smoketest for CRUD users.\" variables : - device_sn : ${gen_random_string(15)} request : base_url : http://127.0.0.1:5000 headers : device_sn : $device_sn - test : name : get token variables : - user_agent : 'iOS/10.3' - os_platform : 'ios' - app_version : '2.8.6' request : url : /api/get-token method : POST headers : user_agent : $user_agent os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : /api/users/1000 method : POST headers : token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, we define variables in config block. Also, we can set base_url in config block, thereby we can specify relative path in each API request url. Besides, we can also set common fields in config request , such as device_sn in headers. Until now, the test cases are finished and each detail is handled properly. Run test cases and generate report \u00b6 Finally, let's run test set quickstart-demo-rev-3.yml once more. $ ate examples/quickstart-demo-rev-4.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 33 ms, response_length: 46 bytes OK (0.037027)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 INFO:root: status_code: 201, response_time: 15 ms, response_length: 54 bytes OK (0.016414)s ---------------------------------------------------------------------- Ran 2 tests in 0.054s OK Generating HTML reports... Template is not specified, load default template instead. Reports generated: /Users/Leo/MyProjects/HttpRunner/reports/quickstart-demo-rev-0/2017-08-01-16-51-51.html Great! The test case runs successfully and generates a HTML test report. Further more \u00b6 This is just a starting point, see the advanced guide for the advanced features. templating data extraction and validation comparator","title":"Quick Start"},{"location":"quickstart/#quick-start","text":"First of all, remember HttpRunner is a simple yet powerful HTTP(S) testing framework. This document will help you to learn HttpRunner in 10 minutes.","title":"Quick Start"},{"location":"quickstart/#write-the-first-test-case","text":"Open your favorite text editor and you can write test cases like this. - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : F8prvGryC5beBr4g json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, each API request is described in a test block. And in the request field, it describes the detail of HTTP request, includes url, method, headers and data, which are in line with the captured traffic. You may wonder why we use the json field other than data . That's because the post data is in JSON format, when we use json to indicate the post data, we do not have to specify Content-Type to be application/json in request headers or dump data before request. Have you recalled some familiar scenes? Yes! That's what we did in requests.request ! Since HttpRunner takes full reuse of Requests , it inherits all powerful features of Requests , and we can handle HTTP request as the way we do before.","title":"Write the first test case"},{"location":"quickstart/#run-test-cases","text":"Suppose the test case file is named as quickstart-demo-rev-0.yml and is located in examples folder, then we can run it in this way. ate examples/demo-rev-0.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 48 ms, response_length: 46 bytes OK (0.049669)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 ERROR:root: Failed to POST http://127.0.0.1:5000/api/users/1000! exception msg: 403 Client Error: FORBIDDEN for url: http://127.0.0.1:5000/api/users/1000 ERROR (0.006471)s ---------------------------------------------------------------------- Ran 2 tests in 0.056s FAILED (Errors=1) Oops! The second test case failed with 403 status code. That is because we request with the same data as we captured in Charles Proxy , while the token is generated dynamically, thus the recorded data can not be be used twice directly.","title":"Run test cases"},{"location":"quickstart/#optimize-test-case-correlation","text":"To fix this problem, we should correlate token field in the second API test case, which is also called correlation . - test : name : get token request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : iOS/10.3 device_sn : 9TN6O2Bn1vzfybF os_platform : ios app_version : 2.8.6 json : sign : 19067cf712265eb5426db8d3664026c1ccea02b9 extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : 9TN6O2Bn1vzfybF token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, the token field is no longer hardcoded, instead it is extracted from the first API request with extract mechanism. In the meanwhile, it is assigned to token variable, which can be referenced by the subsequent API requests. Now we save the test cases to quickstart-demo-rev-1.yml and rerun it, and we will find that both API requests to be successful.","title":"Optimize test case: correlation"},{"location":"quickstart/#optimize-test-case-parameterization","text":"Let's look back to our test set quickstart-demo-rev-1.yml , and we can see the device_sn field is still hardcoded. This may be quite different from the actual scenarios. In actual scenarios, each user's device_sn is different, so we should parameterize the request parameters, which is also called parameterization . In the meanwhile, the sign field is calculated with other header fields, thus it may change significantly if any header field changes slightly. However, the test cases are only YAML documents, it is impossible to generate parameters dynamically in such text. Fortunately, we can combine Python scripts with YAML/JSON test cases in HttpRunner . To achieve this goal, we can utilize debugtalk.py plugin and variables mechanisms. To be specific, we can create a Python file ( examples/debugtalk.py ) and implement the related algorithm in it. The debugtalk.py file can not only be located beside YAML/JSON testcase file, but also can be in any upward recursive folder. Since we want debugtalk.py to be importable, we should put a __init__.py in its folder to make it as a Python module. import hashlib import hmac import random import string SECRET_KEY = \"DebugTalk\" 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 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 And then, we can revise our demo test case and reference the functions. Suppose the revised file named quickstart-demo-rev-2.yml . - test : name : get token variables : - user_agent : 'iOS/10.3' - device_sn : ${gen_random_string(15)} - os_platform : 'ios' - app_version : '2.8.6' request : url : http://127.0.0.1:5000/api/get-token method : POST headers : user_agent : $user_agent device_sn : $device_sn os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : http://127.0.0.1:5000/api/users/1000 method : POST headers : device_sn : $device_sn token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } In this revised test case, variable reference and function invoke mechanisms are both used. To make fields like device_sn can be used more than once, we bind values to variables in variables block. When we bind variables, we can not only bind exact value to a variable name, but also can call a function and bind the evaluated value to it. When we want to reference a variable in the test case, we can do this with a escape character $ . For example, $user_agent will not be taken as a normal string, and HttpRunner will consider it as a variable named user_agent , search and return its binding value. When we want to reference a function, we shall use another escape character ${} . Any content in ${} will be considered as function calling, so we should guarantee that we call functions in the right way. At the same time, variables can also be referenced as parameters of function.","title":"Optimize test case: parameterization"},{"location":"quickstart/#optimize-test-case-overall-config-block","text":"There is still one issue unsolved. The device_sn field is defined in the first API test case, thus it may be impossible to reference it in other test cases. Context separation is a well-designed mechanism, and we should obey this good practice. To handle this case, overall config block is supported in HttpRunner . If we define variables or import functions in config block, these variables and functions will become global and can be referenced in the whole test set. # examples/quickstart-demo-rev-3.yml - config : name : \"smoketest for CRUD users.\" variables : - device_sn : ${gen_random_string(15)} request : base_url : http://127.0.0.1:5000 headers : device_sn : $device_sn - test : name : get token variables : - user_agent : 'iOS/10.3' - os_platform : 'ios' - app_version : '2.8.6' request : url : /api/get-token method : POST headers : user_agent : $user_agent os_platform : $os_platform app_version : $app_version json : sign : ${get_sign($user_agent, $device_sn, $os_platform, $app_version)} extract : - token : content.token validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 200 } - { \"check\" : \"content.token\" , \"comparator\" : \"len_eq\" , \"expect\" : 16 } - test : name : create user which does not exist request : url : /api/users/1000 method : POST headers : token : $token json : name : \"user1\" password : \"123456\" validate : - { \"check\" : \"status_code\" , \"comparator\" : \"eq\" , \"expect\" : 201 } - { \"check\" : \"content.success\" , \"comparator\" : \"eq\" , \"expect\" : true } As you see, we define variables in config block. Also, we can set base_url in config block, thereby we can specify relative path in each API request url. Besides, we can also set common fields in config request , such as device_sn in headers. Until now, the test cases are finished and each detail is handled properly.","title":"Optimize test case: overall config block"},{"location":"quickstart/#run-test-cases-and-generate-report","text":"Finally, let's run test set quickstart-demo-rev-3.yml once more. $ ate examples/quickstart-demo-rev-4.yml Running tests... ---------------------------------------------------------------------- get token ... INFO:root: Start to POST http://127.0.0.1:5000/api/get-token INFO:root: status_code: 200, response_time: 33 ms, response_length: 46 bytes OK (0.037027)s create user which does not exist ... INFO:root: Start to POST http://127.0.0.1:5000/api/users/1000 INFO:root: status_code: 201, response_time: 15 ms, response_length: 54 bytes OK (0.016414)s ---------------------------------------------------------------------- Ran 2 tests in 0.054s OK Generating HTML reports... Template is not specified, load default template instead. Reports generated: /Users/Leo/MyProjects/HttpRunner/reports/quickstart-demo-rev-0/2017-08-01-16-51-51.html Great! The test case runs successfully and generates a HTML test report.","title":"Run test cases and generate report"},{"location":"quickstart/#further-more","text":"This is just a starting point, see the advanced guide for the advanced features. templating data extraction and validation comparator","title":"Further more"},{"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\u4e1a\u754c\u9886\u5148\u7684\u6d4b\u8bd5\u5f00\u53d1\u6280\u672f\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\uff0c\u96b6\u5c5e\u4e8e\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u3002\u5b66\u9662\u8bfe\u7a0b\u5747\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 \u5f00\u6e90\u670d\u52a1\u8d5e\u52a9\u5546\uff08Open Source Sponsor\uff09 \u00b6 HttpRunner is in Sentry Sponsored plan. \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":"Sponsors"},{"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\u4e1a\u754c\u9886\u5148\u7684\u6d4b\u8bd5\u5f00\u53d1\u6280\u672f\u9ad8\u7aef\u6559\u80b2\u54c1\u724c\uff0c\u96b6\u5c5e\u4e8e\u6d4b\u5427\uff08\u5317\u4eac\uff09\u79d1\u6280\u6709\u9650\u516c\u53f8\u3002\u5b66\u9662\u8bfe\u7a0b\u5747\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/#open-source-sponsor","text":"HttpRunner is in Sentry Sponsored plan.","title":"\u5f00\u6e90\u670d\u52a1\u8d5e\u52a9\u5546\uff08Open Source 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":"dev/models/","text":"Models \u00b6 HttpRunner v3.x uses pydantic to define models of testcase.","title":"Models"},{"location":"dev/models/#models","text":"HttpRunner v3.x uses pydantic to define models of testcase.","title":"Models"},{"location":"user/gen_tests/","text":"Record & Generate testcase \u00b6 capture HTTP request and response \u00b6 Before we write testcases, we should know the details of the API. It is a good choice to use a web debugging proxy tool like Charles Proxy to capture the HTTP traffic. For example, the image below illustrates post form data to postman-echo.com . export sessions to HAR file \u00b6 Then we can select captured request & response and export sessions to HTTP archive (.har) file. generate testcase with har2case \u00b6 When you get HAR file, you can use builtin command har2case to convert it to HttpRunner testcase. help \u00b6 $ har2case -h usage: har2case har2case [-h] [-2y] [-2j] [--filter FILTER] [--exclude EXCLUDE] [har_source_file] positional arguments: har_source_file Specify HAR source file optional arguments: -h, --help show this help message and exit -2y, --to-yml, --to-yaml Convert to YAML format, if not specified, convert to pytest format by default. -2j, --to-json Convert to JSON format, if not specified, convert to pytest format by default. --filter FILTER Specify filter keyword, only url include filter string will be converted. --exclude EXCLUDE Specify exclude keyword, url that includes exclude string will be ignored, multiple keywords can be joined with '|' generate testcase (pytest) \u00b6 Since HttpRunner 3.0.7 , har2case will convert HAR file to pytest by default, and it is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. $ har2case har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:08:01.191 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.har 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:08:01.194 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted. 2020-06-15 15:08:01.469 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py The generated pytest file is a standard Python file shown as below. # NOTE: Generated By HttpRunner v3.0.12 # FROM: har/postman-echo-post-form.har from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCasePostmanEchoPostForm ( HttpRunner ): config = Config ( \"testcase description\" ) . verify ( False ) teststeps = [ Step ( RunRequest ( \"/get\" ) . get ( \"https://postman-echo.com/get\" ) . with_params ( ** { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ) ), Step ( RunRequest ( \"/post\" ) . post ( \"https://postman-echo.com/post\" ) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . with_data ({ \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.data\" , \"\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/post\" ) ), ] if __name__ == \"__main__\" : TestCasePostmanEchoPostForm () . test_start () And it can be run with hrun command or the native pytest command. In fact, hrun is only a wrapper of pytest , thus the effect is basically the same. $ hrun har/postman_echo_post_form_test.py 2020-06-15 15:23:03.502 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:23:03.503 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... All done! \u2728 \ud83c\udf70 \u2728 1 file left unchanged. 2020-06-15 15:23:03.662 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.60s ======================================================================= $ pytest har/postman_echo_post_form_test.py ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ================================================================= 1 passed, 1 warning in 4.11s ================================================================== generate testcase (YAML/JSON) \u00b6 Of course, you can also generate former YAML/JSON testcase format. Just add -2y/--to-yml or -2j/--to-json argument to har2case . $ har2case har/postman-echo-post-form.har -2j 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:32:02.958 | INFO | httprunner.ext.har2case.utils:dump_json:122 - dump testcase to JSON format. 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.utils:dump_json:131 - Generate JSON testcase successfully: har/postman-echo-post-form.json 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: har/postman-echo-post-form.json { \"config\" : { \"name\" : \"testcase description\" , \"variables\" : {}, \"verify\" : false }, \"teststeps\" : [ { \"name\" : \"/get\" , \"request\" : { \"url\" : \"https://postman-echo.com/get\" , \"params\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }, \"method\" : \"GET\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ] } ] }, { \"name\" : \"/post\" , \"request\" : { \"url\" : \"https://postman-echo.com/post\" , \"method\" : \"POST\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"data\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.data\" , \"\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/post\" ] } ] } ] } The YAML/JSON testcase has the same info with pytest testcase, and you can run YAML/JSON testcase with hrun command. $ hrun har/postman-echo-post-form.json 2020-06-15 15:37:15.621 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:37:15.623 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.json 2020-06-15 15:37:15.625 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:37:15.625 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted, 1 file left unchanged. 2020-06-15 15:37:15.962 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.03s =======================================================================","title":"Record & Generate testcase"},{"location":"user/gen_tests/#record-generate-testcase","text":"","title":"Record & Generate testcase"},{"location":"user/gen_tests/#capture-http-request-and-response","text":"Before we write testcases, we should know the details of the API. It is a good choice to use a web debugging proxy tool like Charles Proxy to capture the HTTP traffic. For example, the image below illustrates post form data to postman-echo.com .","title":"capture HTTP request and response"},{"location":"user/gen_tests/#export-sessions-to-har-file","text":"Then we can select captured request & response and export sessions to HTTP archive (.har) file.","title":"export sessions to HAR file"},{"location":"user/gen_tests/#generate-testcase-with-har2case","text":"When you get HAR file, you can use builtin command har2case to convert it to HttpRunner testcase.","title":"generate testcase with har2case"},{"location":"user/gen_tests/#help","text":"$ har2case -h usage: har2case har2case [-h] [-2y] [-2j] [--filter FILTER] [--exclude EXCLUDE] [har_source_file] positional arguments: har_source_file Specify HAR source file optional arguments: -h, --help show this help message and exit -2y, --to-yml, --to-yaml Convert to YAML format, if not specified, convert to pytest format by default. -2j, --to-json Convert to JSON format, if not specified, convert to pytest format by default. --filter FILTER Specify filter keyword, only url include filter string will be converted. --exclude EXCLUDE Specify exclude keyword, url that includes exclude string will be ignored, multiple keywords can be joined with '|'","title":"help"},{"location":"user/gen_tests/#generate-testcase-pytest","text":"Since HttpRunner 3.0.7 , har2case will convert HAR file to pytest by default, and it is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. $ har2case har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:08:01.187 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:08:01.191 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:08:01.191 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.har 2020-06-15 15:08:01.193 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:08:01.194 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted. 2020-06-15 15:08:01.469 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py The generated pytest file is a standard Python file shown as below. # NOTE: Generated By HttpRunner v3.0.12 # FROM: har/postman-echo-post-form.har from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCasePostmanEchoPostForm ( HttpRunner ): config = Config ( \"testcase description\" ) . verify ( False ) teststeps = [ Step ( RunRequest ( \"/get\" ) . get ( \"https://postman-echo.com/get\" ) . with_params ( ** { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ) ), Step ( RunRequest ( \"/post\" ) . post ( \"https://postman-echo.com/post\" ) . with_headers ( ** { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" , } ) . with_cookies ( ** { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2 %2F rD9cxUhQemIsm78nifYZYHpPCU\" } ) . with_data ({ \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( 'headers.\"Content-Type\"' , \"application/json; charset=utf-8\" ) . assert_equal ( \"body.data\" , \"\" ) . assert_equal ( \"body.url\" , \"https://postman-echo.com/post\" ) ), ] if __name__ == \"__main__\" : TestCasePostmanEchoPostForm () . test_start () And it can be run with hrun command or the native pytest command. In fact, hrun is only a wrapper of pytest , thus the effect is basically the same. $ hrun har/postman_echo_post_form_test.py 2020-06-15 15:23:03.502 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:23:03.502 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:23:03.503 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... All done! \u2728 \ud83c\udf70 \u2728 1 file left unchanged. 2020-06-15 15:23:03.662 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.60s ======================================================================= $ pytest har/postman_echo_post_form_test.py ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ================================================================= 1 passed, 1 warning in 4.11s ==================================================================","title":"generate testcase (pytest)"},{"location":"user/gen_tests/#generate-testcase-yamljson","text":"Of course, you can also generate former YAML/JSON testcase format. Just add -2y/--to-yml or -2j/--to-json argument to har2case . $ har2case har/postman-echo-post-form.har -2j 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:gen_testcase:332 - Start to generate testcase from har/postman-echo-post-form.har 2020-06-15 15:32:02.955 | INFO | httprunner.ext.har2case.core:_make_testcase:323 - Extract info from HAR file and prepare for testcase. 2020-06-15 15:32:02.958 | INFO | httprunner.ext.har2case.utils:dump_json:122 - dump testcase to JSON format. 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.utils:dump_json:131 - Generate JSON testcase successfully: har/postman-echo-post-form.json 2020-06-15 15:32:02.959 | INFO | httprunner.ext.har2case.core:gen_testcase:353 - generated testcase: har/postman-echo-post-form.json { \"config\" : { \"name\" : \"testcase description\" , \"variables\" : {}, \"verify\" : false }, \"teststeps\" : [ { \"name\" : \"/get\" , \"request\" : { \"url\" : \"https://postman-echo.com/get\" , \"params\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" }, \"method\" : \"GET\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"6606343b-10e5-4165-a89f-6c301b762ce0\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/get?foo1=bar1&foo2=bar2\" ] } ] }, { \"name\" : \"/post\" , \"request\" : { \"url\" : \"https://postman-echo.com/post\" , \"method\" : \"POST\" , \"cookies\" : { \"sails.sid\" : \"s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"headers\" : { \"User-Agent\" : \"PostmanRuntime/7.24.1\" , \"Accept\" : \"*/*\" , \"Cache-Control\" : \"no-cache\" , \"Postman-Token\" : \"3e408e9d-25ca-4b31-b04b-7f4898a8cd49\" , \"Host\" : \"postman-echo.com\" , \"Accept-Encoding\" : \"gzip, deflate, br\" , \"Connection\" : \"keep-alive\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , \"Content-Length\" : \"19\" , \"Cookie\" : \"sails.sid=s%3AQG_EVeNRw8k1xxZ6v_SG401VTpmJDSRu.fTAGx3JnZUT7S0c2%2FrD9cxUhQemIsm78nifYZYHpPCU\" }, \"data\" : { \"foo1\" : \"bar1\" , \"foo2\" : \"bar2\" } }, \"validate\" : [ { \"eq\" : [ \"status_code\" , 200 ] }, { \"eq\" : [ \"headers.Content-Type\" , \"application/json; charset=utf-8\" ] }, { \"eq\" : [ \"body.data\" , \"\" ] }, { \"eq\" : [ \"body.url\" , \"https://postman-echo.com/post\" ] } ] } ] } The YAML/JSON testcase has the same info with pytest testcase, and you can run YAML/JSON testcase with hrun command. $ hrun har/postman-echo-post-form.json 2020-06-15 15:37:15.621 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/Desktop/demo/.env 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 15:37:15.622 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 15:37:15.623 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/Desktop/demo/har/postman-echo-post-form.json 2020-06-15 15:37:15.625 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py 2020-06-15 15:37:15.625 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/Desktop/demo/har/postman_echo_post_form_test.py All done! \u2728 \ud83c\udf70 \u2728 1 file reformatted, 1 file left unchanged. 2020-06-15 15:37:15.962 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/Desktop/demo plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 1 item har/postman_echo_post_form_test.py . [100%] ======================================================================= 1 passed in 2.03s =======================================================================","title":"generate testcase (YAML/JSON)"},{"location":"user/scaffold/","text":"Scaffold \u00b6 If you want to create a new project, you can use the scaffold to startup quickly. help \u00b6 $ httprunner startproject -h usage: httprunner startproject [-h] [project_name] positional arguments: project_name Specify new project name. optional arguments: -h, --help show this help message and exit create new project \u00b6 The only argument you need to specify is the project name. $ httprunner startproject demo 2020-06-15 11:53:25.498 | INFO | httprunner.scaffold:create_scaffold:37 - Create new project: demo Project Root Dir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo created folder: demo created folder: demo/har created folder: demo/testcases created folder: demo/reports created file: demo/testcases/demo_testcase_request.yml created file: demo/testcases/demo_testcase_ref.yml created file: demo/debugtalk.py created file: demo/.env created file: demo/.gitignore $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files If you specify a project name that already exists, you will get a warning. $ httprunner startproject demo 2020-06-15 11:55:03.192 | WARNING | httprunner.scaffold:create_scaffold:32 - Project demo exists, please specify a new project name. $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files run scaffold project \u00b6 The scaffold project has several valid testcases, so you can run tests without any edit. $ hrun demo 2020-06-15 11:57:15.883 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/.env 2020-06-15 11:57:15.883 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 11:57:15.884 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 11:57:15.885 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref.yml 2020-06-15 11:57:15.898 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.899 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py 2020-06-15 11:57:15.900 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py 2020-06-15 11:57:15.911 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.912 | INFO | httprunner.make:__ensure_project_meta_files:128 - copy .env to /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/_env 2020-06-15 11:57:15.912 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py All done! \u2728 \ud83c\udf70 \u2728 2 files reformatted, 1 file left unchanged. 2020-06-15 11:57:16.299 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 2 items demo/testcases/demo_testcase_request_test.py . [ 50%] demo/testcases/demo_testcase_ref_test.py . [100%] ======================================================================= 2 passed in 6.87s =======================================================================","title":"Scaffold"},{"location":"user/scaffold/#scaffold","text":"If you want to create a new project, you can use the scaffold to startup quickly.","title":"Scaffold"},{"location":"user/scaffold/#help","text":"$ httprunner startproject -h usage: httprunner startproject [-h] [project_name] positional arguments: project_name Specify new project name. optional arguments: -h, --help show this help message and exit","title":"help"},{"location":"user/scaffold/#create-new-project","text":"The only argument you need to specify is the project name. $ httprunner startproject demo 2020-06-15 11:53:25.498 | INFO | httprunner.scaffold:create_scaffold:37 - Create new project: demo Project Root Dir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo created folder: demo created folder: demo/har created folder: demo/testcases created folder: demo/reports created file: demo/testcases/demo_testcase_request.yml created file: demo/testcases/demo_testcase_ref.yml created file: demo/debugtalk.py created file: demo/.env created file: demo/.gitignore $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files If you specify a project name that already exists, you will get a warning. $ httprunner startproject demo 2020-06-15 11:55:03.192 | WARNING | httprunner.scaffold:create_scaffold:32 - Project demo exists, please specify a new project name. $ tree demo -a demo \u251c\u2500\u2500 .env \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 debugtalk.py \u251c\u2500\u2500 har \u251c\u2500\u2500 reports \u2514\u2500\u2500 testcases \u251c\u2500\u2500 demo_testcase_ref.yml \u2514\u2500\u2500 demo_testcase_request.yml 3 directories, 5 files","title":"create new project"},{"location":"user/scaffold/#run-scaffold-project","text":"The scaffold project has several valid testcases, so you can run tests without any edit. $ hrun demo 2020-06-15 11:57:15.883 | INFO | httprunner.loader:load_dot_env_file:130 - Loading environment variables from /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/.env 2020-06-15 11:57:15.883 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: USERNAME 2020-06-15 11:57:15.884 | DEBUG | httprunner.utils:set_os_environ:32 - Set OS environment variable: PASSWORD 2020-06-15 11:57:15.885 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref.yml 2020-06-15 11:57:15.898 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.899 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py 2020-06-15 11:57:15.900 | INFO | httprunner.make:make_testcase:383 - generated testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py 2020-06-15 11:57:15.911 | INFO | httprunner.make:make_testcase:310 - start to make testcase: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request.yml 2020-06-15 11:57:15.912 | INFO | httprunner.make:__ensure_project_meta_files:128 - copy .env to /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/_env 2020-06-15 11:57:15.912 | INFO | httprunner.make:format_pytest_with_black:147 - format pytest cases with black ... reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_ref_test.py reformatted /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner/demo/testcases/demo_testcase_request_test.py All done! \u2728 \ud83c\udf70 \u2728 2 files reformatted, 1 file left unchanged. 2020-06-15 11:57:16.299 | INFO | httprunner.cli:main_run:56 - start to run tests with pytest. HttpRunner version: 3.0.12 ====================================================================== test session starts ====================================================================== platform darwin -- Python 3.7.5, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 rootdir: /Users/debugtalk/MyProjects/HttpRunner-dev/HttpRunner plugins: metadata-1.9.0, allure-pytest-2.8.16, html-2.1.1 collected 2 items demo/testcases/demo_testcase_request_test.py . [ 50%] demo/testcases/demo_testcase_ref_test.py . [100%] ======================================================================= 2 passed in 6.87s =======================================================================","title":"run scaffold project"},{"location":"user/write_testcase/","text":"Write Testcase \u00b6 HttpRunner v3.x supports three testcase formats, pytest , YAML and JSON . It is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. The format relations are illustrated as below: record & generate testcase \u00b6 If the SUT (system under test) is ready, the most efficient way is to capture HTTP traffic first and then generate testcases with HAR file. Refer to Record & Generate testcase for more details. Based on the generated pytest testcase, you can then do some adjustment as needed, thus you need to know the details of testcase format. testcase structure \u00b6 Each testcase is a subclass of HttpRunner , and must have two class attributes: config and teststeps . config: configure testcase level settings, including base_url , verify , variables , export . teststeps: list of teststep ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Besides, variables / extract / validate / hooks mechanisms are supported to create extremely complex test scenarios. from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCaseRequestWithFunctions ( HttpRunner ): config = ( Config ( \"request methods testcase with functions\" ) . variables ( ** { \"foo1\" : \"config_bar1\" , \"foo2\" : \"config_bar2\" , \"expect_foo1\" : \"config_bar1\" , \"expect_foo2\" : \"config_bar2\" , } ) . base_url ( \"https://postman-echo.com\" ) . verify ( False ) . export ( * [ \"foo3\" ]) ) teststeps = [ Step ( RunRequest ( \"get with params\" ) . with_variables ( ** { \"foo1\" : \"bar11\" , \"foo2\" : \"bar21\" , \"sum_v\" : \"${sum_two(1, 2)}\" } ) . get ( \"/get\" ) . with_params ( ** { \"foo1\" : \"$foo1\" , \"foo2\" : \"$foo2\" , \"sum_v\" : \"$sum_v\" }) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" }) . extract () . with_jmespath ( \"body.args.foo2\" , \"foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.args.foo1\" , \"bar11\" ) . assert_equal ( \"body.args.sum_v\" , \"3\" ) . assert_equal ( \"body.args.foo2\" , \"bar21\" ) ), Step ( RunRequest ( \"post form data\" ) . with_variables ( ** { \"foo2\" : \"bar23\" }) . post ( \"/post\" ) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , } ) . with_data ( \"foo1=$foo1&foo2=$foo2&foo3=$foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.form.foo1\" , \"$expect_foo1\" ) . assert_equal ( \"body.form.foo2\" , \"bar23\" ) . assert_equal ( \"body.form.foo3\" , \"bar21\" ) ), ] if __name__ == \"__main__\" : TestCaseRequestWithFunctions () . test_start () chain call \u00b6 One of the most awesome features of HttpRunner v3.x is chain call , with which you do not need to remember any testcase format details and you can get intelligent completion when you write testcases in IDE. config \u00b6 Each testcase should have one config part, in which you can configure testcase level settings. name (required) \u00b6 Specify testcase name. This will be displayed in execution log and test report. base_url (optional) \u00b6 Specify common schema and host part of the SUT, e.g. https://postman-echo.com . If base_url is specified, url in teststep can only set relative path part. This is especially useful if you want to switch between different SUT environments. variables (optional) \u00b6 Specify common variables of testcase. Each teststep can reference config variable which is not set in step variables. In other words, step variables have higher priority than config variables. verify (optional) \u00b6 Specify whether to verify the server\u2019s TLS certificate. This is especially useful if we want to record HTTP traffic of testcase execution, because SSLError will be occurred if verify is not set or been set to True. SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1076)')) export (optional) \u00b6 Specify the exported session variables of testcase. Consider each testcase as a black box, config variables is the input part, and config export is the output part. In particular, when a testcase is referenced in another testcase's step, and will be extracted some session variables to be used in subsequent teststeps, then the extracted session variables should be configured in config export part. teststeps \u00b6 Each testcase should have one or multiple ordered test steps ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Notice: The concept of API in HttpRunner v2.x has been deprecated for simplification. You can consider API as a testcase that has only one request step. RunRequest(name) \u00b6 RunRequest is used in a step to make request to API and do some extraction or validations for response. The argument name of RunRequest is used to specify teststep name, which will be displayed in execution log and test report. .with_variables \u00b6 Specify teststep variables. The variables of each step are independent, thus if you want to share variables in multiple steps, you should define variables in config variables. Besides, the step variables will override the ones that have the same name in config variables. .method(url) \u00b6 Specify HTTP method and the url of SUT. These are corresponding to method and url arguments of requests.request . If base_url is set in config, url can only set relative path part. .with_params \u00b6 Specify query string for the request url. This is corresponding to the params argument of requests.request . .with_headers \u00b6 Specify HTTP headers for the request. This is corresponding to the headers argument of requests.request . .with_cookies \u00b6 Specify HTTP request cookies. This is corresponding to the cookies argument of requests.request . .with_data \u00b6 Specify HTTP request body. This is corresponding to the data argument of requests.request . .with_json \u00b6 Specify HTTP request body in json. This is corresponding to the json argument of requests.request . extract \u00b6 .with_jmespath \u00b6 Extract JSON response body with jmespath . with_jmespath(jmes_path: Text, var_name: Text) jmes_path: jmespath expression, refer to JMESPath Tutorial for more details var_name: the variable name that stores extracted value, it can be referenced by subsequent test steps validate \u00b6 .assert_XXX \u00b6 Extract JSON response body with jmespath and validate with expected value. assert_XXX(jmes_path: Text, expected_value: Any) jmes_path: jmespath expression, refer to JMESPath Tutorial for more details expected_value: the specified expected value, variable or function reference can also be used here The image below shows HttpRunner builtin validators. RunTestCase(name) \u00b6 RunTestCase is used in a step to reference another testcase call. The argument name of RunTestCase is used to specify teststep name, which will be displayed in execution log and test report. .with_variables \u00b6 Same with RunRequest's .with_variables .","title":"Write Testcase"},{"location":"user/write_testcase/#write-testcase","text":"HttpRunner v3.x supports three testcase formats, pytest , YAML and JSON . It is extremely recommended to write and maintain testcases in pytest format instead of former YAML/JSON format. The format relations are illustrated as below:","title":"Write Testcase"},{"location":"user/write_testcase/#record-generate-testcase","text":"If the SUT (system under test) is ready, the most efficient way is to capture HTTP traffic first and then generate testcases with HAR file. Refer to Record & Generate testcase for more details. Based on the generated pytest testcase, you can then do some adjustment as needed, thus you need to know the details of testcase format.","title":"record & generate testcase"},{"location":"user/write_testcase/#testcase-structure","text":"Each testcase is a subclass of HttpRunner , and must have two class attributes: config and teststeps . config: configure testcase level settings, including base_url , verify , variables , export . teststeps: list of teststep ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Besides, variables / extract / validate / hooks mechanisms are supported to create extremely complex test scenarios. from httprunner import HttpRunner , Config , Step , RunRequest , RunTestCase class TestCaseRequestWithFunctions ( HttpRunner ): config = ( Config ( \"request methods testcase with functions\" ) . variables ( ** { \"foo1\" : \"config_bar1\" , \"foo2\" : \"config_bar2\" , \"expect_foo1\" : \"config_bar1\" , \"expect_foo2\" : \"config_bar2\" , } ) . base_url ( \"https://postman-echo.com\" ) . verify ( False ) . export ( * [ \"foo3\" ]) ) teststeps = [ Step ( RunRequest ( \"get with params\" ) . with_variables ( ** { \"foo1\" : \"bar11\" , \"foo2\" : \"bar21\" , \"sum_v\" : \"${sum_two(1, 2)}\" } ) . get ( \"/get\" ) . with_params ( ** { \"foo1\" : \"$foo1\" , \"foo2\" : \"$foo2\" , \"sum_v\" : \"$sum_v\" }) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" }) . extract () . with_jmespath ( \"body.args.foo2\" , \"foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.args.foo1\" , \"bar11\" ) . assert_equal ( \"body.args.sum_v\" , \"3\" ) . assert_equal ( \"body.args.foo2\" , \"bar21\" ) ), Step ( RunRequest ( \"post form data\" ) . with_variables ( ** { \"foo2\" : \"bar23\" }) . post ( \"/post\" ) . with_headers ( ** { \"User-Agent\" : \"HttpRunner/${get_httprunner_version()}\" , \"Content-Type\" : \"application/x-www-form-urlencoded\" , } ) . with_data ( \"foo1=$foo1&foo2=$foo2&foo3=$foo3\" ) . validate () . assert_equal ( \"status_code\" , 200 ) . assert_equal ( \"body.form.foo1\" , \"$expect_foo1\" ) . assert_equal ( \"body.form.foo2\" , \"bar23\" ) . assert_equal ( \"body.form.foo3\" , \"bar21\" ) ), ] if __name__ == \"__main__\" : TestCaseRequestWithFunctions () . test_start ()","title":"testcase structure"},{"location":"user/write_testcase/#chain-call","text":"One of the most awesome features of HttpRunner v3.x is chain call , with which you do not need to remember any testcase format details and you can get intelligent completion when you write testcases in IDE.","title":"chain call"},{"location":"user/write_testcase/#config","text":"Each testcase should have one config part, in which you can configure testcase level settings.","title":"config"},{"location":"user/write_testcase/#name-required","text":"Specify testcase name. This will be displayed in execution log and test report.","title":"name (required)"},{"location":"user/write_testcase/#base_url-optional","text":"Specify common schema and host part of the SUT, e.g. https://postman-echo.com . If base_url is specified, url in teststep can only set relative path part. This is especially useful if you want to switch between different SUT environments.","title":"base_url (optional)"},{"location":"user/write_testcase/#variables-optional","text":"Specify common variables of testcase. Each teststep can reference config variable which is not set in step variables. In other words, step variables have higher priority than config variables.","title":"variables (optional)"},{"location":"user/write_testcase/#verify-optional","text":"Specify whether to verify the server\u2019s TLS certificate. This is especially useful if we want to record HTTP traffic of testcase execution, because SSLError will be occurred if verify is not set or been set to True. SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1076)'))","title":"verify (optional)"},{"location":"user/write_testcase/#export-optional","text":"Specify the exported session variables of testcase. Consider each testcase as a black box, config variables is the input part, and config export is the output part. In particular, when a testcase is referenced in another testcase's step, and will be extracted some session variables to be used in subsequent teststeps, then the extracted session variables should be configured in config export part.","title":"export (optional)"},{"location":"user/write_testcase/#teststeps","text":"Each testcase should have one or multiple ordered test steps ( List[Step] ), each step is corresponding to a API request or another testcase reference call. Notice: The concept of API in HttpRunner v2.x has been deprecated for simplification. You can consider API as a testcase that has only one request step.","title":"teststeps"},{"location":"user/write_testcase/#runrequestname","text":"RunRequest is used in a step to make request to API and do some extraction or validations for response. The argument name of RunRequest is used to specify teststep name, which will be displayed in execution log and test report.","title":"RunRequest(name)"},{"location":"user/write_testcase/#with_variables","text":"Specify teststep variables. The variables of each step are independent, thus if you want to share variables in multiple steps, you should define variables in config variables. Besides, the step variables will override the ones that have the same name in config variables.","title":".with_variables"},{"location":"user/write_testcase/#methodurl","text":"Specify HTTP method and the url of SUT. These are corresponding to method and url arguments of requests.request . If base_url is set in config, url can only set relative path part.","title":".method(url)"},{"location":"user/write_testcase/#with_params","text":"Specify query string for the request url. This is corresponding to the params argument of requests.request .","title":".with_params"},{"location":"user/write_testcase/#with_headers","text":"Specify HTTP headers for the request. This is corresponding to the headers argument of requests.request .","title":".with_headers"},{"location":"user/write_testcase/#with_cookies","text":"Specify HTTP request cookies. This is corresponding to the cookies argument of requests.request .","title":".with_cookies"},{"location":"user/write_testcase/#with_data","text":"Specify HTTP request body. This is corresponding to the data argument of requests.request .","title":".with_data"},{"location":"user/write_testcase/#with_json","text":"Specify HTTP request body in json. This is corresponding to the json argument of requests.request .","title":".with_json"},{"location":"user/write_testcase/#extract","text":"","title":"extract"},{"location":"user/write_testcase/#with_jmespath","text":"Extract JSON response body with jmespath . with_jmespath(jmes_path: Text, var_name: Text) jmes_path: jmespath expression, refer to JMESPath Tutorial for more details var_name: the variable name that stores extracted value, it can be referenced by subsequent test steps","title":".with_jmespath"},{"location":"user/write_testcase/#validate","text":"","title":"validate"},{"location":"user/write_testcase/#assert_xxx","text":"Extract JSON response body with jmespath and validate with expected value. assert_XXX(jmes_path: Text, expected_value: Any) jmes_path: jmespath expression, refer to JMESPath Tutorial for more details expected_value: the specified expected value, variable or function reference can also be used here The image below shows HttpRunner builtin validators.","title":".assert_XXX"},{"location":"user/write_testcase/#runtestcasename","text":"RunTestCase is used in a step to reference another testcase call. The argument name of RunTestCase is used to specify teststep name, which will be displayed in execution log and test report.","title":"RunTestCase(name)"},{"location":"user/write_testcase/#with_variables_1","text":"Same with RunRequest's .with_variables .","title":".with_variables"}]}
\ No newline at end of file
diff --git a/sitemap.xml b/sitemap.xml
index 08488436..ea02234a 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -1,31 +1,31 @@
HttpRunner v3.x supports three testcase formats, pytest
, YAML
and JSON
. It is extremely recommended to write and maintain testcases in pytest
format instead of former YAML/JSON
format.
The format relations are illustrated as below:
+If the SUT (system under test) is ready, the most efficient way is to capture HTTP traffic first and then generate testcases with HAR file. Refer to Record & Generate testcase
for more details.
Based on the generated pytest testcase, you can then do some adjustment as needed, thus you need to know the details of testcase format.
@@ -884,13 +912,26 @@with_jmespath(jmes_path: Text, var_name: Text)
Extract JSON response body with jmespath and validate with expected value.
+++assert_XXX(jmes_path: Text, expected_value: Any)
+
The image below shows HttpRunner builtin validators.
+RunTestCase
is used in a step to reference another testcase call.
The argument name
of RunTestCase is used to specify teststep name, which will be displayed in execution log and test report.
Besides, variables
/extract
/validate
/hooks
mechanisms are supported to create extremely complex test scenarios.
Same with RunRequest's .with_variables
.