mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-26 02:40:05 +08:00
change: generate pytest in chain style by default
This commit is contained in:
@@ -1,87 +1,69 @@
|
|||||||
# NOTICE: Generated By HttpRunner. DO NOT EDIT!
|
# NOTICE: Generated By HttpRunner. DO NOT EDIT!
|
||||||
# FROM: examples/postman_echo/request_methods/request_with_functions.yml
|
# FROM: examples/postman_echo/request_methods/request_with_functions.yml
|
||||||
|
|
||||||
from httprunner import HttpRunner, TConfig, TStep
|
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||||
|
|
||||||
|
|
||||||
class TestCaseRequestWithFunctions(HttpRunner):
|
class TestCaseRequestWithFunctions(HttpRunner):
|
||||||
config = TConfig(
|
config = (
|
||||||
**{
|
Config("request methods testcase with functions")
|
||||||
"name": "request methods testcase with functions",
|
.variables(**{"foo1": "session_bar1"})
|
||||||
"variables": {"foo1": "session_bar1"},
|
.base_url("https://postman-echo.com")
|
||||||
"base_url": "https://postman-echo.com",
|
.verify(False)
|
||||||
"verify": False,
|
|
||||||
"path": "examples/postman_echo/request_methods/request_with_functions_test.py",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
teststeps = [
|
teststeps = [
|
||||||
TStep(
|
Step(
|
||||||
**{
|
RunRequest("get with params")
|
||||||
"name": "get with params",
|
.with_variables(
|
||||||
"variables": {
|
**{"foo1": "bar1", "foo2": "session_bar2", "sum_v": "${sum_two(1, 2)}"}
|
||||||
"foo1": "bar1",
|
)
|
||||||
"foo2": "session_bar2",
|
.get("/get")
|
||||||
"sum_v": "${sum_two(1, 2)}",
|
.with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
|
||||||
},
|
.with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
|
||||||
"request": {
|
.extract()
|
||||||
"method": "GET",
|
.with_jmespath("body.args.foo2", "session_foo2")
|
||||||
"url": "/get",
|
.validate()
|
||||||
"params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"},
|
.assert_equal("status_code", 200)
|
||||||
"headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"},
|
.assert_equal("body.args.foo1", "session_bar1")
|
||||||
},
|
.assert_equal("body.args.sum_v", "3")
|
||||||
"extract": {"session_foo2": "body.args.foo2"},
|
.assert_equal("body.args.foo2", "session_bar2")
|
||||||
"validate": [
|
|
||||||
{"eq": ["status_code", 200]},
|
|
||||||
{"eq": ["body.args.foo1", "session_bar1"]},
|
|
||||||
{"eq": ["body.args.sum_v", "3"]},
|
|
||||||
{"eq": ["body.args.foo2", "session_bar2"]},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
),
|
||||||
TStep(
|
Step(
|
||||||
**{
|
RunRequest("post raw text")
|
||||||
"name": "post raw text",
|
.with_variables(**{"foo1": "hello world", "foo3": "$session_foo2"})
|
||||||
"variables": {"foo1": "hello world", "foo3": "$session_foo2"},
|
.post("/post")
|
||||||
"request": {
|
.with_headers(
|
||||||
"method": "POST",
|
**{
|
||||||
"url": "/post",
|
"User-Agent": "HttpRunner/${get_httprunner_version()}",
|
||||||
"headers": {
|
"Content-Type": "text/plain",
|
||||||
"User-Agent": "HttpRunner/${get_httprunner_version()}",
|
}
|
||||||
"Content-Type": "text/plain",
|
)
|
||||||
},
|
.with_data(
|
||||||
"data": "This is expected to be sent back as part of response body: $foo1-$foo3.",
|
"This is expected to be sent back as part of response body: $foo1-$foo3."
|
||||||
},
|
)
|
||||||
"validate": [
|
.validate()
|
||||||
{"eq": ["status_code", 200]},
|
.assert_equal("status_code", 200)
|
||||||
{
|
.assert_equal(
|
||||||
"eq": [
|
"body.data",
|
||||||
"body.data",
|
"This is expected to be sent back as part of response body: session_bar1-session_bar2.",
|
||||||
"This is expected to be sent back as part of response body: session_bar1-session_bar2.",
|
)
|
||||||
]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
),
|
||||||
TStep(
|
Step(
|
||||||
**{
|
RunRequest("post form data")
|
||||||
"name": "post form data",
|
.with_variables(**{"foo1": "bar1", "foo2": "bar2"})
|
||||||
"variables": {"foo1": "bar1", "foo2": "bar2"},
|
.post("/post")
|
||||||
"request": {
|
.with_headers(
|
||||||
"method": "POST",
|
**{
|
||||||
"url": "/post",
|
"User-Agent": "HttpRunner/${get_httprunner_version()}",
|
||||||
"headers": {
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
"User-Agent": "HttpRunner/${get_httprunner_version()}",
|
}
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
)
|
||||||
},
|
.with_data("foo1=$foo1&foo2=$foo2")
|
||||||
"data": "foo1=$foo1&foo2=$foo2",
|
.validate()
|
||||||
},
|
.assert_equal("status_code", 200)
|
||||||
"validate": [
|
.assert_equal("body.form.foo1", "session_bar1")
|
||||||
{"eq": ["status_code", 200]},
|
.assert_equal("body.form.foo2", "bar2")
|
||||||
{"eq": ["body.form.foo1", "session_bar1"]},
|
|
||||||
{"eq": ["body.form.foo2", "bar2"]},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,9 @@ def main_run(extra_args):
|
|||||||
# keep compatibility with v2
|
# keep compatibility with v2
|
||||||
extra_args = ensure_cli_args(extra_args)
|
extra_args = ensure_cli_args(extra_args)
|
||||||
|
|
||||||
chain_style = False
|
|
||||||
tests_path_list = []
|
tests_path_list = []
|
||||||
extra_args_new = []
|
extra_args_new = []
|
||||||
for item in extra_args:
|
for item in extra_args:
|
||||||
if item == "--chain-style":
|
|
||||||
chain_style = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not os.path.exists(item):
|
if not os.path.exists(item):
|
||||||
# item is not file/folder path
|
# item is not file/folder path
|
||||||
extra_args_new.append(item)
|
extra_args_new.append(item)
|
||||||
@@ -43,7 +38,7 @@ def main_run(extra_args):
|
|||||||
logger.error(f"No valid testcase path in cli arguments: {extra_args}")
|
logger.error(f"No valid testcase path in cli arguments: {extra_args}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
testcase_path_list = main_make(tests_path_list, chain_style=chain_style)
|
testcase_path_list = main_make(tests_path_list)
|
||||||
if not testcase_path_list:
|
if not testcase_path_list:
|
||||||
logger.error("No valid testcases found, exit 1.")
|
logger.error("No valid testcases found, exit 1.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -115,7 +110,7 @@ def main():
|
|||||||
elif sys.argv[1] == "har2case":
|
elif sys.argv[1] == "har2case":
|
||||||
main_har2case(args)
|
main_har2case(args)
|
||||||
elif sys.argv[1] == "make":
|
elif sys.argv[1] == "make":
|
||||||
main_make(args.testcase_path, chain_style=args.chain_style)
|
main_make(args.testcase_path)
|
||||||
|
|
||||||
|
|
||||||
def main_hrun_alias():
|
def main_hrun_alias():
|
||||||
|
|||||||
@@ -29,35 +29,6 @@ __TEMPLATE__ = jinja2.Template(
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, os.getcwd())
|
|
||||||
{% endif %}
|
|
||||||
from httprunner import HttpRunner, TConfig, TStep
|
|
||||||
{% for import_str in imports_list %}
|
|
||||||
{{ import_str }}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
class {{ class_name }}(HttpRunner):
|
|
||||||
config = TConfig(**{{ config }})
|
|
||||||
|
|
||||||
teststeps = [
|
|
||||||
{% for teststep in teststeps %}
|
|
||||||
TStep(**{{ teststep }}),
|
|
||||||
{% endfor %}
|
|
||||||
]
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
{{ class_name }}().test_start()
|
|
||||||
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
__TEMPLATE_CHAIN_STYLE__ = jinja2.Template(
|
|
||||||
"""# NOTICE: Generated By HttpRunner. DO NOT EDIT!
|
|
||||||
# FROM: {{ testcase_path }}
|
|
||||||
{% if imports_list %}
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.insert(0, os.getcwd())
|
sys.path.insert(0, os.getcwd())
|
||||||
{% endif %}
|
{% endif %}
|
||||||
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
|
||||||
@@ -231,7 +202,7 @@ def make_teststep_chain_style(teststep: Dict) -> Text:
|
|||||||
if teststep.get("request"):
|
if teststep.get("request"):
|
||||||
step_info += make_request_chain_style(teststep["request"])
|
step_info += make_request_chain_style(teststep["request"])
|
||||||
elif teststep.get("testcase"):
|
elif teststep.get("testcase"):
|
||||||
testcase = teststep["testcase"].replace("CLS_LB(", "").replace(")CLS_RB", "")
|
testcase = teststep["testcase"]
|
||||||
call_ref_testcase = f".call({testcase})"
|
call_ref_testcase = f".call({testcase})"
|
||||||
step_info += call_ref_testcase
|
step_info += call_ref_testcase
|
||||||
|
|
||||||
@@ -248,19 +219,21 @@ def make_teststep_chain_style(teststep: Dict) -> Text:
|
|||||||
validator = uniform_validator(v)
|
validator = uniform_validator(v)
|
||||||
assert_method = validator["assert"]
|
assert_method = validator["assert"]
|
||||||
check = validator["check"]
|
check = validator["check"]
|
||||||
|
if '"' in check:
|
||||||
|
# e.g. body."user-agent" => 'body."user-agent"'
|
||||||
|
check = f"'{check}'"
|
||||||
|
else:
|
||||||
|
check = f'"{check}"'
|
||||||
expect = validator["expect"]
|
expect = validator["expect"]
|
||||||
if isinstance(expect, Text):
|
if isinstance(expect, Text):
|
||||||
expect = f'"{expect}"'
|
expect = f'"{expect}"'
|
||||||
step_info += f'.assert_{assert_method}("{check}", {expect})'
|
step_info += f'.assert_{assert_method}({check}, {expect})'
|
||||||
|
|
||||||
return f"Step({step_info})"
|
return f"Step({step_info})"
|
||||||
|
|
||||||
|
|
||||||
def __make_testcase(
|
def __make_testcase(
|
||||||
testcase: Dict,
|
testcase: Dict, dir_path: Text = None, ref_flag: bool = False,
|
||||||
dir_path: Text = None,
|
|
||||||
ref_flag: bool = False,
|
|
||||||
chain_style: bool = False,
|
|
||||||
) -> NoReturn:
|
) -> NoReturn:
|
||||||
"""convert valid testcase dict to pytest file path"""
|
"""convert valid testcase dict to pytest file path"""
|
||||||
# ensure compatibility with testcase format v2
|
# ensure compatibility with testcase format v2
|
||||||
@@ -309,7 +282,7 @@ def __make_testcase(
|
|||||||
ref_testcase_python_path, ref_testcase_cls_name = convert_testcase_path(
|
ref_testcase_python_path, ref_testcase_cls_name = convert_testcase_path(
|
||||||
ref_testcase_path
|
ref_testcase_path
|
||||||
)
|
)
|
||||||
teststep["testcase"] = f"CLS_LB({ref_testcase_cls_name})CLS_RB"
|
teststep["testcase"] = ref_testcase_cls_name
|
||||||
|
|
||||||
# prepare import ref testcase
|
# prepare import ref testcase
|
||||||
ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1 :]
|
ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1 :]
|
||||||
@@ -323,19 +296,12 @@ def __make_testcase(
|
|||||||
"testcase_path": __ensure_cwd_relative(testcase_path),
|
"testcase_path": __ensure_cwd_relative(testcase_path),
|
||||||
"class_name": f"TestCase{testcase_cls_name}",
|
"class_name": f"TestCase{testcase_cls_name}",
|
||||||
"imports_list": imports_list,
|
"imports_list": imports_list,
|
||||||
}
|
"config_chain_style": make_config_chain_style(config),
|
||||||
|
"teststeps_chain_style": [
|
||||||
if chain_style:
|
|
||||||
data["config_chain_style"] = make_config_chain_style(config)
|
|
||||||
data["teststeps_chain_style"] = [
|
|
||||||
make_teststep_chain_style(step) for step in teststeps
|
make_teststep_chain_style(step) for step in teststeps
|
||||||
]
|
],
|
||||||
content = __TEMPLATE_CHAIN_STYLE__.render(data)
|
}
|
||||||
else:
|
content = __TEMPLATE__.render(data)
|
||||||
data["config"] = config
|
|
||||||
data["teststeps"] = teststeps
|
|
||||||
content = __TEMPLATE__.render(data)
|
|
||||||
content = content.replace("'CLS_LB(", "").replace(")CLS_RB'", "")
|
|
||||||
|
|
||||||
with open(testcase_python_path, "w", encoding="utf-8") as f:
|
with open(testcase_python_path, "w", encoding="utf-8") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
@@ -348,7 +314,7 @@ def __make_testcase(
|
|||||||
make_files_cache_set.add(__ensure_cwd_relative(testcase_python_path))
|
make_files_cache_set.add(__ensure_cwd_relative(testcase_python_path))
|
||||||
|
|
||||||
|
|
||||||
def __make_testsuite(testsuite: Dict, chain_style: bool = False) -> NoReturn:
|
def __make_testsuite(testsuite: Dict) -> NoReturn:
|
||||||
"""convert valid testsuite dict to pytest folder with testcases"""
|
"""convert valid testsuite dict to pytest folder with testcases"""
|
||||||
# validate testsuite format
|
# validate testsuite format
|
||||||
load_testsuite(testsuite)
|
load_testsuite(testsuite)
|
||||||
@@ -393,12 +359,10 @@ def __make_testsuite(testsuite: Dict, chain_style: bool = False) -> NoReturn:
|
|||||||
testcase_dict["config"]["variables"].update(testsuite_variables)
|
testcase_dict["config"]["variables"].update(testsuite_variables)
|
||||||
|
|
||||||
# make testcase
|
# make testcase
|
||||||
__make_testcase(testcase_dict, testsuite_dir, chain_style=chain_style)
|
__make_testcase(testcase_dict, testsuite_dir)
|
||||||
|
|
||||||
|
|
||||||
def __make(
|
def __make(tests_path: Text, ref_flag: bool = False) -> NoReturn:
|
||||||
tests_path: Text, ref_flag: bool = False, chain_style: bool = False
|
|
||||||
) -> NoReturn:
|
|
||||||
""" make testcase(s) with testcase/testsuite/folder absolute path
|
""" make testcase(s) with testcase/testsuite/folder absolute path
|
||||||
generated pytest file path will be cached in make_files_cache_set
|
generated pytest file path will be cached in make_files_cache_set
|
||||||
|
|
||||||
@@ -432,16 +396,14 @@ def __make(
|
|||||||
# testcase
|
# testcase
|
||||||
if "teststeps" in test_content:
|
if "teststeps" in test_content:
|
||||||
try:
|
try:
|
||||||
__make_testcase(
|
__make_testcase(test_content, ref_flag=ref_flag)
|
||||||
test_content, ref_flag=ref_flag, chain_style=chain_style
|
|
||||||
)
|
|
||||||
except exceptions.TestCaseFormatError:
|
except exceptions.TestCaseFormatError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# testsuite
|
# testsuite
|
||||||
elif "testcases" in test_content:
|
elif "testcases" in test_content:
|
||||||
try:
|
try:
|
||||||
__make_testsuite(test_content, chain_style=chain_style)
|
__make_testsuite(test_content)
|
||||||
except exceptions.TestSuiteFormatError:
|
except exceptions.TestSuiteFormatError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -452,12 +414,12 @@ def __make(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main_make(tests_paths: List[Text], chain_style: bool = False) -> List[Text]:
|
def main_make(tests_paths: List[Text]) -> List[Text]:
|
||||||
for tests_path in tests_paths:
|
for tests_path in tests_paths:
|
||||||
if not os.path.isabs(tests_path):
|
if not os.path.isabs(tests_path):
|
||||||
tests_path = os.path.join(os.getcwd(), tests_path)
|
tests_path = os.path.join(os.getcwd(), tests_path)
|
||||||
|
|
||||||
__make(tests_path, chain_style=chain_style)
|
__make(tests_path)
|
||||||
|
|
||||||
testcase_path_list = list(make_files_cache_set)
|
testcase_path_list = list(make_files_cache_set)
|
||||||
__format_pytest_with_black(testcase_path_list)
|
__format_pytest_with_black(testcase_path_list)
|
||||||
@@ -473,11 +435,5 @@ def init_make_parser(subparsers):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"testcase_path", nargs="*", help="Specify YAML/JSON testcase file/folder path"
|
"testcase_path", nargs="*", help="Specify YAML/JSON testcase file/folder path"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--chain-style",
|
|
||||||
dest="chain_style",
|
|
||||||
action="store_true",
|
|
||||||
help="Convert pytest files in chain-style.",
|
|
||||||
)
|
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List, Dict, Text, NoReturn, Union
|
from typing import List, Dict, Text, NoReturn
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import allure
|
import allure
|
||||||
@@ -35,8 +35,8 @@ from httprunner.schema import (
|
|||||||
|
|
||||||
|
|
||||||
class HttpRunner(object):
|
class HttpRunner(object):
|
||||||
config: Union[TConfig, Config]
|
config: Config
|
||||||
teststeps: List[Union[TStep, Step]]
|
teststeps: List[Step]
|
||||||
|
|
||||||
success: bool = True # indicate testcase execution result
|
success: bool = True # indicate testcase execution result
|
||||||
__config: TConfig
|
__config: TConfig
|
||||||
@@ -53,21 +53,10 @@ class HttpRunner(object):
|
|||||||
__log_path: Text = ""
|
__log_path: Text = ""
|
||||||
|
|
||||||
def __init_tests__(self) -> NoReturn:
|
def __init_tests__(self) -> NoReturn:
|
||||||
if isinstance(self.config, TConfig):
|
self.__config = self.config.perform()
|
||||||
self.__config = self.config
|
|
||||||
elif isinstance(self.config, Config):
|
|
||||||
self.__config = self.config.perform()
|
|
||||||
else:
|
|
||||||
raise exceptions.TestCaseFormatError(f"config type error: {self.config}")
|
|
||||||
|
|
||||||
self.__teststeps = []
|
self.__teststeps = []
|
||||||
for step in self.teststeps:
|
for step in self.teststeps:
|
||||||
if isinstance(step, TStep):
|
self.__teststeps.append(step.perform())
|
||||||
self.__teststeps.append(step)
|
|
||||||
elif isinstance(step, Step):
|
|
||||||
self.__teststeps.append(step.perform())
|
|
||||||
else:
|
|
||||||
raise exceptions.TestCaseFormatError(f"step type error: {step}")
|
|
||||||
|
|
||||||
def with_project_meta(self, project_meta: ProjectMeta) -> "HttpRunner":
|
def with_project_meta(self, project_meta: ProjectMeta) -> "HttpRunner":
|
||||||
self.__project_meta = project_meta
|
self.__project_meta = project_meta
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ teststeps:
|
|||||||
validate:
|
validate:
|
||||||
- eq: ["status_code", 200]
|
- eq: ["status_code", 200]
|
||||||
- eq: ["body.args.foo1", "session_bar1"]
|
- eq: ["body.args.foo1", "session_bar1"]
|
||||||
- eq: ["body.args.sum_v", 3]
|
- eq: ["body.args.sum_v", "3"]
|
||||||
- eq: ["body.args.foo2", "session_bar2"]
|
- eq: ["body.args.foo2", "session_bar2"]
|
||||||
-
|
-
|
||||||
name: post raw text
|
name: post raw text
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ class RunTestCase(object):
|
|||||||
|
|
||||||
def call(self, testcase: Callable):
|
def call(self, testcase: Callable):
|
||||||
self.__t_step.testcase = testcase
|
self.__t_step.testcase = testcase
|
||||||
|
return self
|
||||||
|
|
||||||
def perform(self) -> TStep:
|
def perform(self) -> TStep:
|
||||||
return self.__t_step
|
return self.__t_step
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ from examples.postman_echo.request_methods.request_with_functions_test import (
|
|||||||
content,
|
content,
|
||||||
)
|
)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'"testcase": RequestWithFunctions,', content,
|
'.call(RequestWithFunctions)', content,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_make_testcase_folder(self):
|
def test_make_testcase_folder(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user