mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-12 16:01:27 +08:00
feat: make referenced testcase as pytest class
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## 3.0.6 (2020-05-23)
|
## 3.0.6 (2020-05-23)
|
||||||
|
|
||||||
|
**Added**
|
||||||
|
|
||||||
|
- feat: make referenced testcase as pytest class
|
||||||
|
|
||||||
**Fixed**
|
**Fixed**
|
||||||
|
|
||||||
- fix: ensure converted python file in utf-8 encoding
|
- fix: ensure converted python file in utf-8 encoding
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
# FROM: examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference.yml
|
# FROM: examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference.yml
|
||||||
from httprunner import HttpRunner, TConfig, TStep
|
from httprunner import HttpRunner, TConfig, TStep
|
||||||
|
|
||||||
|
from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||||
|
TestCaseRequestWithFunctions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestCaseRequestWithTestcaseReference(HttpRunner):
|
class TestCaseRequestWithTestcaseReference(HttpRunner):
|
||||||
config = TConfig(
|
config = TConfig(
|
||||||
@@ -19,7 +23,7 @@ class TestCaseRequestWithTestcaseReference(HttpRunner):
|
|||||||
**{
|
**{
|
||||||
"name": "request with functions",
|
"name": "request with functions",
|
||||||
"variables": {"foo1": "override_bar1"},
|
"variables": {"foo1": "override_bar1"},
|
||||||
"testcase": "request_methods/request_with_functions.yml",
|
"testcase": TestCaseRequestWithFunctions,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
# FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml
|
# FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml
|
||||||
from httprunner import HttpRunner, TConfig, TStep
|
from httprunner import HttpRunner, TConfig, TStep
|
||||||
|
|
||||||
|
from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||||
|
TestCaseRequestWithFunctions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestCaseRequestWithTestcaseReference(HttpRunner):
|
class TestCaseRequestWithTestcaseReference(HttpRunner):
|
||||||
config = TConfig(
|
config = TConfig(
|
||||||
@@ -19,7 +23,7 @@ class TestCaseRequestWithTestcaseReference(HttpRunner):
|
|||||||
**{
|
**{
|
||||||
"name": "request with functions",
|
"name": "request with functions",
|
||||||
"variables": {"foo1": "override_bar1"},
|
"variables": {"foo1": "override_bar1"},
|
||||||
"testcase": "request_methods/request_with_functions.yml",
|
"testcase": TestCaseRequestWithFunctions,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ from httprunner.parser import parse_data
|
|||||||
__TMPL__ = """# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
|
__TMPL__ = """# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
|
||||||
# FROM: {{ testcase_path }}
|
# FROM: {{ testcase_path }}
|
||||||
from httprunner import HttpRunner, TConfig, TStep
|
from httprunner import HttpRunner, TConfig, TStep
|
||||||
|
{% for import_str in imports_list %}
|
||||||
|
{{ import_str }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
class {{ class_name }}(HttpRunner):
|
class {{ class_name }}(HttpRunner):
|
||||||
@@ -55,8 +58,9 @@ def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]:
|
|||||||
|
|
||||||
# convert title case, e.g. request_with_variables => RequestWithVariables
|
# convert title case, e.g. request_with_variables => RequestWithVariables
|
||||||
name_in_title_case = file_name.title().replace("_", "")
|
name_in_title_case = file_name.title().replace("_", "")
|
||||||
|
testcase_cls_name = f"TestCase{name_in_title_case}"
|
||||||
|
|
||||||
return testcase_python_path, name_in_title_case
|
return testcase_python_path, testcase_cls_name
|
||||||
|
|
||||||
|
|
||||||
def format_pytest_with_black(python_paths: List[Text]):
|
def format_pytest_with_black(python_paths: List[Text]):
|
||||||
@@ -81,10 +85,15 @@ def make_testcase(testcase: Dict) -> Union[str, None]:
|
|||||||
|
|
||||||
template = jinja2.Template(__TMPL__)
|
template = jinja2.Template(__TMPL__)
|
||||||
|
|
||||||
testcase_python_path, name_in_title_case = convert_testcase_path(testcase_path)
|
# convert abs path to relative
|
||||||
|
if os.path.isabs(testcase_path):
|
||||||
|
testcase_path = testcase_path[len(os.getcwd()) + 1 :]
|
||||||
|
testcase_python_path, testcase_cls_name = convert_testcase_path(testcase_path)
|
||||||
|
|
||||||
config = testcase["config"]
|
config = testcase["config"]
|
||||||
|
config["path"] = testcase_python_path
|
||||||
|
|
||||||
|
# parse config variables
|
||||||
config.setdefault("variables", {})
|
config.setdefault("variables", {})
|
||||||
if isinstance(config["variables"], Text):
|
if isinstance(config["variables"], Text):
|
||||||
# get variables by function, e.g. ${get_variables()}
|
# get variables by function, e.g. ${get_variables()}
|
||||||
@@ -93,14 +102,41 @@ def make_testcase(testcase: Dict) -> Union[str, None]:
|
|||||||
config["variables"], {}, project_meta.functions
|
config["variables"], {}, project_meta.functions
|
||||||
)
|
)
|
||||||
|
|
||||||
config["path"] = testcase_python_path
|
# prepare reference testcase
|
||||||
|
imports_list = []
|
||||||
|
teststeps = testcase["teststeps"]
|
||||||
|
for teststep in teststeps:
|
||||||
|
if not teststep.get("testcase"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
ref_testcase_path = teststep["testcase"]
|
||||||
|
|
||||||
|
# make ref testcase pytest file
|
||||||
|
project_meta = load_project_meta(testcase_path)
|
||||||
|
ref_testcase_path = os.path.join(project_meta.PWD, ref_testcase_path)
|
||||||
|
__make(ref_testcase_path)
|
||||||
|
|
||||||
|
# prepare ref testcase class name
|
||||||
|
ref_testcase_python_path, ref_testcase_cls_name = convert_testcase_path(
|
||||||
|
ref_testcase_path
|
||||||
|
)
|
||||||
|
teststep["testcase"] = f"CLS_LB({ref_testcase_cls_name})CLS_RB"
|
||||||
|
|
||||||
|
# prepare import ref testcase
|
||||||
|
ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1 :]
|
||||||
|
ref_module_name, _ = os.path.splitext(ref_testcase_python_path)
|
||||||
|
ref_module_name = ref_module_name.replace(os.sep, ".")
|
||||||
|
imports_list.append(f"from {ref_module_name} import {ref_testcase_cls_name}")
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"testcase_path": testcase_path,
|
"testcase_path": testcase_path,
|
||||||
"class_name": f"TestCase{name_in_title_case}",
|
"class_name": testcase_cls_name,
|
||||||
"config": config,
|
"config": config,
|
||||||
"teststeps": testcase["teststeps"],
|
"teststeps": teststeps,
|
||||||
|
"imports_list": imports_list,
|
||||||
}
|
}
|
||||||
content = template.render(data)
|
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)
|
||||||
|
|||||||
@@ -12,6 +12,25 @@ class TestLoader(unittest.TestCase):
|
|||||||
"examples/postman_echo/request_methods/request_with_variables_test.py",
|
"examples/postman_echo/request_methods/request_with_variables_test.py",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_make_testcase_with_ref(self):
|
||||||
|
path = [
|
||||||
|
"examples/postman_echo/request_methods/request_with_testcase_reference.yml"
|
||||||
|
]
|
||||||
|
testcase_python_list = main_make(path)
|
||||||
|
with open(testcase_python_list[0]) as f:
|
||||||
|
content = f.read()
|
||||||
|
self.assertIn(
|
||||||
|
"""
|
||||||
|
from examples.postman_echo.request_methods.request_with_functions_test import (
|
||||||
|
TestCaseRequestWithFunctions,
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
content,
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'"testcase": TestCaseRequestWithFunctions,', content,
|
||||||
|
)
|
||||||
|
|
||||||
def test_make_testcase_folder(self):
|
def test_make_testcase_folder(self):
|
||||||
path = ["examples/postman_echo/request_methods/"]
|
path = ["examples/postman_echo/request_methods/"]
|
||||||
testcase_python_list = main_make(path)
|
testcase_python_list = main_make(path)
|
||||||
@@ -33,26 +52,28 @@ class TestLoader(unittest.TestCase):
|
|||||||
"/path/to 2/mubu_login_test.py",
|
"/path/to 2/mubu_login_test.py",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
convert_testcase_path("/path/to 2/mubu.login.yml")[1], "MubuLogin"
|
convert_testcase_path("/path/to 2/mubu.login.yml")[1], "TestCaseMubuLogin"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
convert_testcase_path("mubu login.yml")[0], "mubu_login_test.py"
|
convert_testcase_path("mubu login.yml")[0], "mubu_login_test.py"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
convert_testcase_path("/path/to 2/mubu login.yml")[1], "MubuLogin"
|
convert_testcase_path("/path/to 2/mubu login.yml")[1], "TestCaseMubuLogin"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
convert_testcase_path("/path/to 2/mubu-login.yml")[0],
|
convert_testcase_path("/path/to 2/mubu-login.yml")[0],
|
||||||
"/path/to 2/mubu_login_test.py",
|
"/path/to 2/mubu_login_test.py",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
convert_testcase_path("/path/to 2/mubu-login.yml")[1], "MubuLogin"
|
convert_testcase_path("/path/to 2/mubu-login.yml")[1], "TestCaseMubuLogin"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
convert_testcase_path("/path/to 2/幕布login.yml")[0],
|
convert_testcase_path("/path/to 2/幕布login.yml")[0],
|
||||||
"/path/to 2/幕布login_test.py",
|
"/path/to 2/幕布login_test.py",
|
||||||
)
|
)
|
||||||
self.assertEqual(convert_testcase_path("/path/to/幕布login.yml")[1], "幕布Login")
|
self.assertEqual(
|
||||||
|
convert_testcase_path("/path/to/幕布login.yml")[1], "TestCase幕布Login"
|
||||||
|
)
|
||||||
|
|
||||||
def test_make_testsuite(self):
|
def test_make_testsuite(self):
|
||||||
path = ["examples/postman_echo/request_methods/demo_testsuite.yml"]
|
path = ["examples/postman_echo/request_methods/demo_testsuite.yml"]
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ def multipart_encoder(**kwargs) -> MultipartEncoder:
|
|||||||
else:
|
else:
|
||||||
# value is not absolute file path, check if it is relative file path
|
# value is not absolute file path, check if it is relative file path
|
||||||
from httprunner.loader import load_project_meta
|
from httprunner.loader import load_project_meta
|
||||||
|
|
||||||
project_meta = load_project_meta(os.getcwd())
|
project_meta = load_project_meta(os.getcwd())
|
||||||
|
|
||||||
_file_path = os.path.join(project_meta.PWD, value)
|
_file_path = os.path.join(project_meta.PWD, value)
|
||||||
|
|||||||
@@ -141,14 +141,35 @@ class HttpRunner(object):
|
|||||||
step_data = StepData(name=step.name)
|
step_data = StepData(name=step.name)
|
||||||
step_variables = step.variables
|
step_variables = step.variables
|
||||||
|
|
||||||
ref_testcase_path = os.path.join(self.__project_meta.PWD, step.testcase)
|
if hasattr(step.testcase, "config") and hasattr(step.testcase, "teststeps"):
|
||||||
case_result = (
|
testcase_cls = step.testcase
|
||||||
HttpRunner()
|
case_result = (
|
||||||
.with_session(self.__session)
|
testcase_cls()
|
||||||
.with_case_id(self.__case_id)
|
.with_session(self.__session)
|
||||||
.with_variables(step_variables)
|
.with_case_id(self.__case_id)
|
||||||
.run_path(ref_testcase_path)
|
.with_variables(step_variables)
|
||||||
)
|
.run()
|
||||||
|
)
|
||||||
|
|
||||||
|
elif isinstance(step.testcase, Text):
|
||||||
|
if os.path.isabs(step.testcase):
|
||||||
|
ref_testcase_path = step.testcase
|
||||||
|
else:
|
||||||
|
ref_testcase_path = os.path.join(self.__project_meta.PWD, step.testcase)
|
||||||
|
|
||||||
|
case_result = (
|
||||||
|
HttpRunner()
|
||||||
|
.with_session(self.__session)
|
||||||
|
.with_case_id(self.__case_id)
|
||||||
|
.with_variables(step_variables)
|
||||||
|
.run_path(ref_testcase_path)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise exceptions.ParamsError(
|
||||||
|
f"Invalid teststep referenced testcase: {step}"
|
||||||
|
)
|
||||||
|
|
||||||
step_data.data = case_result.get_step_datas() # list of step data
|
step_data.data = case_result.get_step_datas() # list of step data
|
||||||
step_data.export = case_result.get_export_variables()
|
step_data.export = case_result.get_export_variables()
|
||||||
step_data.success = case_result.success
|
step_data.success = case_result.success
|
||||||
@@ -186,7 +207,13 @@ class HttpRunner(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def run_testcase(self, testcase: TestCase):
|
def run_testcase(self, testcase: TestCase):
|
||||||
"""run testcase"""
|
"""run specified testcase
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> testcase_obj = TestCase(config=TConfig(...), teststeps=[TStep(...)])
|
||||||
|
>>> HttpRunner().with_project_meta(project_meta).run_testcase(testcase_obj)
|
||||||
|
|
||||||
|
"""
|
||||||
self.config = testcase.config
|
self.config = testcase.config
|
||||||
self.teststeps = testcase.teststeps
|
self.teststeps = testcase.teststeps
|
||||||
|
|
||||||
@@ -224,6 +251,16 @@ class HttpRunner(object):
|
|||||||
testcase_obj = load_testcase_file(path)
|
testcase_obj = load_testcase_file(path)
|
||||||
return self.run_testcase(testcase_obj)
|
return self.run_testcase(testcase_obj)
|
||||||
|
|
||||||
|
def run(self) -> "HttpRunner":
|
||||||
|
""" run current testcase
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> TestCaseRequestWithFunctions().run()
|
||||||
|
|
||||||
|
"""
|
||||||
|
testcase_obj = TestCase(config=self.config, teststeps=self.teststeps)
|
||||||
|
return self.run_testcase(testcase_obj)
|
||||||
|
|
||||||
def get_step_datas(self) -> List[StepData]:
|
def get_step_datas(self) -> List[StepData]:
|
||||||
return self.__step_datas
|
return self.__step_datas
|
||||||
|
|
||||||
@@ -284,7 +321,9 @@ class HttpRunner(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.run_testcase(TestCase(config=self.config, teststeps=self.teststeps))
|
return self.run_testcase(
|
||||||
|
TestCase(config=self.config, teststeps=self.teststeps)
|
||||||
|
)
|
||||||
finally:
|
finally:
|
||||||
logger.remove(log_handler)
|
logger.remove(log_handler)
|
||||||
logger.info(f"generate testcase log: {self.__log_path}")
|
logger.info(f"generate testcase log: {self.__log_path}")
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class Request(BaseModel):
|
|||||||
class TStep(BaseModel):
|
class TStep(BaseModel):
|
||||||
name: Name
|
name: Name
|
||||||
request: Request = None
|
request: Request = None
|
||||||
testcase: Text = ""
|
testcase: Union[Text, Callable] = ""
|
||||||
variables: VariablesMapping = {}
|
variables: VariablesMapping = {}
|
||||||
extract: Dict[Text, Text] = {}
|
extract: Dict[Text, Text] = {}
|
||||||
validators: Validators = Field([], alias="validate")
|
validators: Validators = Field([], alias="validate")
|
||||||
|
|||||||
Reference in New Issue
Block a user