feat: convert YAML/JSON testcase to python testcase

This commit is contained in:
debugtalk
2020-05-14 16:46:52 +08:00
parent 9ba550bd9f
commit 202f040c1c
4 changed files with 267 additions and 80 deletions

View File

@@ -2,89 +2,81 @@ from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep from httprunner.schema import TestsConfig, TestStep
class TestCaseRequestMethodsWithVariables(TestCaseRunner): class TestCaseRequestWithVariables(TestCaseRunner):
config = TestsConfig(**{ config = TestsConfig(
"name": "request methods testcase with variables", **{
"variables": { "name": "request methods testcase with variables",
"foo1": "session_bar1" "variables": {"foo1": "session_bar1"},
}, "base_url": "https://postman-echo.com",
"base_url": "https://postman-echo.com", "verify": False,
"verify": False }
}) )
teststeps = [ teststeps = [
TestStep(**{ TestStep(
"name": "get with params", **{
"variables": { "name": "get with params",
"foo1": "bar1", "variables": {"foo1": "bar1", "foo2": "session_bar2"},
"foo2": "session_bar2" "request": {
}, "method": "GET",
"request": { "url": "/get",
"method": "GET", "params": {"foo1": "$foo1", "foo2": "$foo2"},
"url": "/get", "headers": {"User-Agent": "HttpRunner/3.0"},
"params": {
"foo1": "$foo1",
"foo2": "$foo2"
}, },
"headers": { "extract": {"session_foo2": "body.args.foo2"},
"User-Agent": "HttpRunner/3.0" "validate": [
} {"eq": ["status_code", 200]},
}, {"eq": ["body.args.foo1", "session_bar1"]},
"extract": { {"eq": ["body.args.foo2", "session_bar2"]},
"session_foo2": "body.args.foo2" ],
}, }
"validate": [ ),
{"eq": ["status_code", 200]}, TestStep(
{"eq": ["body.args.foo1", "session_bar1"]}, **{
{"eq": ["body.args.foo2", "session_bar2"]} "name": "post raw text",
] "variables": {"foo1": "hello world", "foo3": "$session_foo2"},
}), "request": {
TestStep(**{ "method": "POST",
"name": "post raw text", "url": "/post",
"variables": { "headers": {
"foo1": "hello world", "User-Agent": "HttpRunner/3.0",
"foo3": "$session_foo2" "Content-Type": "text/plain",
}, },
"request": { "data": "This is expected to be sent back as part of response body: $foo1-$foo3.",
"method": "POST", },
"url": "/post", "validate": [
"data": "This is expected to be sent back as part of response body: $foo1-$foo3.", {"eq": ["status_code", 200]},
"headers": { {
"User-Agent": "HttpRunner/3.0", "eq": [
"Content-Type": "text/plain" "body.data",
} "This is expected to be sent back as part of response body: session_bar1-session_bar2.",
}, ]
"validate": [ },
{"eq": ["status_code", 200]}, ],
{"eq": [ }
"body.data", ),
"This is expected to be sent back as part of response body: session_bar1-session_bar2." TestStep(
]}, **{
] "name": "post form data",
}), "variables": {"foo1": "bar1", "foo2": "bar2"},
TestStep(**{ "request": {
"name": "post form data", "method": "POST",
"variables": { "url": "/post",
"foo1": "session_bar1", "headers": {
"foo2": "bar2" "User-Agent": "HttpRunner/3.0",
}, "Content-Type": "application/x-www-form-urlencoded",
"request": { },
"method": "POST", "data": "foo1=$foo1&foo2=$foo2",
"url": "/post", },
"data": "foo1=$foo1&foo2=$foo2", "validate": [
"headers": { {"eq": ["status_code", 200]},
"User-Agent": "HttpRunner/3.0", {"eq": ["body.form.foo1", "session_bar1"]},
"Content-Type": "application/x-www-form-urlencoded" {"eq": ["body.form.foo2", "bar2"]},
} ],
}, }
"validate": [ ),
{"eq": ["status_code", 200]},
{"eq": ["body.form.foo1", "session_bar1"]},
{"eq": ["body.form.foo2", "bar2"]}
]
})
] ]
if __name__ == '__main__': if __name__ == "__main__":
TestCaseRequestMethodsWithVariables().run() TestCaseRequestWithVariables().run()

11
httprunner/loader_test.py Normal file
View File

@@ -0,0 +1,11 @@
import unittest
from httprunner.new_loader import load_testcase_file
class TestLoader(unittest.TestCase):
def test_load_testcase_file(self):
path = "examples/postman_echo/request_methods/request_with_variables.yml"
testcase = load_testcase_file(path)
self.assertEqual(testcase.config.name, "request methods testcase with variables")
self.assertEqual(len(testcase.teststeps), 3)

49
httprunner/make.py Normal file
View File

@@ -0,0 +1,49 @@
import os
import jinja2
from loguru import logger
from httprunner.new_loader import load_testcase_file
__TMPL__ = """
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
class {{ class_name }}(TestCaseRunner):
config = TestsConfig(**{{ config }})
teststeps = [
{% for teststep in teststeps %}
TestStep(**{{ teststep }}),
{% endfor %}
]
if __name__ == '__main__':
{{ class_name }}().run()
"""
def make_testcase(path: str) -> str:
testcase = load_testcase_file(path)
template = jinja2.Template(__TMPL__)
raw_file_name, _ = os.path.splitext(os.path.basename(path))
# convert title case, e.g. request_with_variables => RequestWithVariables
name_in_title_case = raw_file_name.title().replace("_", "")
data = {
"class_name": f"TestCase{name_in_title_case}",
"config": testcase["config"],
"teststeps": testcase["teststeps"],
}
content = template.render(data)
testcase_dir = os.path.dirname(path)
testcase_python_path = os.path.join(testcase_dir, f"{raw_file_name}_test.py")
with open(testcase_python_path, "w") as f:
f.write(content)
logger.info(f"generated testcase: {testcase_python_path}")
return testcase_python_path

135
httprunner/new_loader.py Normal file
View File

@@ -0,0 +1,135 @@
import io
import json
import os
import types
import yaml
from loguru import logger
from httprunner import builtin
from httprunner import exceptions
from httprunner.schema import TestCase
try:
# PyYAML version >= 5.1
# ref: https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation
yaml.warnings({"YAMLLoadWarning": False})
except AttributeError:
pass
def _load_yaml_file(yaml_file):
""" load yaml file and check file content format
"""
with io.open(yaml_file, "r", encoding="utf-8") as stream:
try:
yaml_content = yaml.load(stream)
except yaml.YAMLError as ex:
logger.error(str(ex))
raise exceptions.FileFormatError
return yaml_content
def _load_json_file(json_file):
""" load json file and check file content format
"""
with io.open(json_file, encoding="utf-8") as data_file:
try:
json_content = json.load(data_file)
except json.JSONDecodeError:
err_msg = f"JSONDecodeError: JSON file format error: {json_file}"
logger.error(err_msg)
raise exceptions.FileFormatError(err_msg)
return json_content
def load_testcase_file(testcase_file):
"""load testcase file and validate with pydantic model"""
file_suffix = os.path.splitext(testcase_file)[1].lower()
if file_suffix == ".json":
testcase_content = _load_json_file(testcase_file)
elif file_suffix in [".yaml", ".yml"]:
testcase_content = _load_yaml_file(testcase_file)
else:
# '' or other suffix
raise exceptions.FileFormatError(
f"testcase file should be YAML/JSON format, invalid testcase file: {testcase_file}"
)
# validate with pydantic TestCase model
TestCase.parse_obj(testcase_content)
return testcase_content
def load_folder_files(folder_path, recursive=True):
""" load folder path, return all files endswith yml/yaml/json in list.
Args:
folder_path (str): specified folder path to load
recursive (bool): load files recursively if True
Returns:
list: files endswith yml/yaml/json
"""
if isinstance(folder_path, (list, set)):
files = []
for path in set(folder_path):
files.extend(load_folder_files(path, recursive))
return files
if not os.path.exists(folder_path):
return []
file_list = []
for dirpath, dirnames, filenames in os.walk(folder_path):
filenames_list = []
for filename in filenames:
if not filename.endswith((".yml", ".yaml", ".json")):
continue
filenames_list.append(filename)
for filename in filenames_list:
file_path = os.path.join(dirpath, filename)
file_list.append(file_path)
if not recursive:
break
return file_list
def load_module_functions(module):
""" load python module functions.
Args:
module: python module
Returns:
dict: functions mapping for specified python module
{
"func1_name": func1,
"func2_name": func2
}
"""
module_functions = {}
for name, item in vars(module).items():
if isinstance(item, types.FunctionType):
module_functions[name] = item
return module_functions
def load_builtin_functions():
""" load builtin module functions
"""
return load_module_functions(builtin)