change: python testcase template

This commit is contained in:
debugtalk
2020-05-14 22:34:18 +08:00
parent ba0611a09a
commit f88845d9d4
13 changed files with 575 additions and 363 deletions

View File

@@ -1,83 +1,79 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
class TestCaseRequestMethodsHardcode(TestCaseRunner):
config = TestsConfig(**{
"name": "request methods testcase in hardcode",
"base_url": "https://postman-echo.com",
"verify": False
})
class TestCaseHardcode(unittest.TestCase):
config = TestsConfig(
**{
"name": "request methods testcase in hardcode",
"base_url": "https://postman-echo.com",
"verify": False,
"path": "examples/postman_echo/request_methods/hardcode_test.py",
}
)
teststeps = [
TestStep(**{
"name": "get with params",
"request": {
"method": "GET",
"url": "/get",
"params": {
"foo1": "bar1",
"foo2": "bar2"
TestStep(
**{
"name": "get with params",
"request": {
"method": "GET",
"url": "/get",
"params": {"foo1": "bar1", "foo2": "bar2"},
"headers": {"User-Agent": "HttpRunner/3.0"},
},
"headers": {
"User-Agent": "HttpRunner/3.0"
}
},
"extract": {
"server": "headers.Server"
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["headers.Server", "nginx"]}
]
}),
TestStep(**{
"name": "post raw text",
"request": {
"method": "POST",
"url": "/post",
"data": "This is expected to be sent back as part of response body.",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "text/plain"
}
},
"validate": [
{"eq": ["status_code", 200]}
]
}),
TestStep(**{
"name": "post form data",
"request": {
"method": "POST",
"url": "/post",
"data": "foo1=bar1&foo2=bar2",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "application/x-www-form-urlencoded"
}
},
"validate": [
{"eq": ["status_code", 200]}
]
}),
TestStep(**{
"name": "put request",
"request": {
"method": "PUT",
"url": "/put",
"data": "This is expected to be sent back as part of response body.",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "text/plain"
}
},
"validate": [
{"eq": ["status_code", 200]}
]
})
"validate": [{"eq": ["status_code", 200]}],
}
),
TestStep(
**{
"name": "post raw text",
"request": {
"method": "POST",
"url": "/post",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "text/plain",
},
"data": "This is expected to be sent back as part of response body.",
},
"validate": [{"eq": ["status_code", 200]}],
}
),
TestStep(
**{
"name": "post form data",
"request": {
"method": "POST",
"url": "/post",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "application/x-www-form-urlencoded",
},
"data": "foo1=bar1&foo2=bar2",
},
"validate": [{"eq": ["status_code", 200]}],
}
),
TestStep(
**{
"name": "put request",
"request": {
"method": "PUT",
"url": "/put",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "text/plain",
},
"data": "This is expected to be sent back as part of response body.",
},
"validate": [{"eq": ["status_code", 200]}],
}
),
]
if __name__ == '__main__':
TestCaseRequestMethodsHardcode().run()
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()

View File

@@ -1,98 +1,90 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
from examples.postman_echo import debugtalk
class TestCaseRequestMethodsWithFunctions(TestCaseRunner):
config = TestsConfig(**{
"name": "request methods testcase with functions",
"variables": {
"foo1": "session_bar1"
},
"functions": {
"get_httprunner_version": debugtalk.get_httprunner_version,
"sum_two": debugtalk.sum_two
},
"base_url": "https://postman-echo.com",
"verify": False
})
class TestCaseRequestWithFunctions(unittest.TestCase):
config = TestsConfig(
**{
"name": "request methods testcase with functions",
"variables": {"foo1": "session_bar1"},
"base_url": "https://postman-echo.com",
"verify": False,
"path": "examples/postman_echo/request_methods/request_with_functions_test.py",
}
)
teststeps = [
TestStep(**{
"name": "get with params",
"variables": {
"foo1": "bar1",
"foo2": "session_bar2",
"sum_v": "${sum_two(1, 2)}"
},
"request": {
"method": "GET",
"url": "/get",
"params": {
"foo1": "$foo1",
"foo2": "$foo2",
"sum_v": "$sum_v"
TestStep(
**{
"name": "get with params",
"variables": {
"foo1": "bar1",
"foo2": "session_bar2",
"sum_v": "${sum_two(1, 2)}",
},
"headers": {
"User-Agent": "HttpRunner/${get_httprunner_version()}"
}
},
"extract": {
"session_foo2": "body.args.foo2"
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.args.foo1", "session_bar1"]},
{"eq": ["body.args.foo2", "session_bar2"]},
{"eq": ["body.args.sum_v", 3]}
]
}),
TestStep(**{
"name": "post raw text",
"variables": {
"foo1": "hello world",
"foo3": "$session_foo2"
},
"request": {
"method": "POST",
"url": "/post",
"data": "This is expected to be sent back as part of response body: $foo1-$foo3.",
"headers": {
"User-Agent": "HttpRunner/${get_httprunner_version()}",
"Content-Type": "text/plain"
}
},
"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": "session_bar1",
"foo2": "bar2"
},
"request": {
"method": "POST",
"url": "/post",
"data": "foo1=$foo1&foo2=$foo2",
"headers": {
"User-Agent": "HttpRunner/${get_httprunner_version()}",
"Content-Type": "application/x-www-form-urlencoded"
}
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.form.foo1", "session_bar1"]},
{"eq": ["body.form.foo2", "bar2"]}
]
})
"request": {
"method": "GET",
"url": "/get",
"params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"},
"headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"},
},
"extract": {"session_foo2": "body.args.foo2"},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.args.foo1", "session_bar1"]},
{"eq": ["body.args.sum_v", 3]},
{"eq": ["body.args.foo2", "session_bar2"]},
],
}
),
TestStep(
**{
"name": "post raw text",
"variables": {"foo1": "hello world", "foo3": "$session_foo2"},
"request": {
"method": "POST",
"url": "/post",
"headers": {
"User-Agent": "HttpRunner/${get_httprunner_version()}",
"Content-Type": "text/plain",
},
"data": "This is expected to be sent back as part of response body: $foo1-$foo3.",
},
"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"},
"request": {
"method": "POST",
"url": "/post",
"headers": {
"User-Agent": "HttpRunner/${get_httprunner_version()}",
"Content-Type": "application/x-www-form-urlencoded",
},
"data": "foo1=$foo1&foo2=$foo2",
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.form.foo1", "session_bar1"]},
{"eq": ["body.form.foo2", "bar2"]},
],
}
),
]
if __name__ == '__main__':
TestCaseRequestMethodsWithFunctions().run()
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()

View File

@@ -1,34 +1,30 @@
from examples.postman_echo import debugtalk
from examples.postman_echo.request_methods.validate_with_variables_test \
import TestCaseRequestMethodsValidateWithVariables
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
class TestCaseRequestMethodsRefTestcase(TestCaseRunner):
config = TestsConfig(**{
"name": "request methods testcase: reference testcase",
"variables": {
"foo1": "session_bar1"
},
"functions": {
"get_httprunner_version": debugtalk.get_httprunner_version,
"sum_two": debugtalk.sum_two
},
"base_url": "https://postman-echo.com",
"verify": False
})
class TestCaseRequestWithTestcaseReference(unittest.TestCase):
config = TestsConfig(
**{
"name": "request methods testcase: reference testcase",
"variables": {"foo1": "session_bar1"},
"base_url": "https://postman-echo.com",
"verify": False,
"path": "examples/postman_echo/request_methods/request_with_testcase_reference_test.py",
}
)
teststeps = [
TestStep(**{
"name": "get with params",
"variables": {
"foo1": "override_bar1"
},
"testcase": TestCaseRequestMethodsValidateWithVariables
})
TestStep(
**{
"name": "request with variables",
"variables": {"foo1": "override_bar1"},
"testcase": "request_methods/request_with_variables.yml",
}
),
]
if __name__ == '__main__':
TestCaseRequestMethodsRefTestcase().run()
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()

View File

@@ -1,14 +1,18 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
class TestCaseRequestWithVariables(TestCaseRunner):
class TestCaseRequestWithVariables(unittest.TestCase):
config = TestsConfig(
**{
"name": "request methods testcase with variables",
"variables": {"foo1": "session_bar1"},
"base_url": "https://postman-echo.com",
"verify": False,
"path": "examples/postman_echo/request_methods/request_with_variables_test.py",
}
)
@@ -77,6 +81,5 @@ class TestCaseRequestWithVariables(TestCaseRunner):
),
]
if __name__ == "__main__":
TestCaseRequestWithVariables().run()
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()

View File

@@ -1,53 +1,45 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
from examples.postman_echo import debugtalk
class TestCaseRequestMethodsValidateWithFunctions(TestCaseRunner):
config = TestsConfig(**{
"name": "request methods testcase: validate with functions",
"variables": {
"foo1": "session_bar1"
},
"functions": {
"get_httprunner_version": debugtalk.get_httprunner_version,
"sum_two": debugtalk.sum_two
},
"base_url": "https://postman-echo.com",
"verify": False
})
class TestCaseValidateWithFunctions(unittest.TestCase):
config = TestsConfig(
**{
"name": "request methods testcase: validate with functions",
"variables": {"foo1": "session_bar1"},
"base_url": "https://postman-echo.com",
"verify": False,
"path": "examples/postman_echo/request_methods/validate_with_functions_test.py",
}
)
teststeps = [
TestStep(**{
"name": "get with params",
"variables": {
"foo1": "bar1",
"foo2": "session_bar2",
"sum_v": "${sum_two(1, 2)}"
},
"request": {
"method": "GET",
"url": "/get",
"params": {
"foo1": "$foo1",
"foo2": "$foo2",
"sum_v": "$sum_v"
TestStep(
**{
"name": "get with params",
"variables": {
"foo1": "bar1",
"foo2": "session_bar2",
"sum_v": "${sum_two(1, 2)}",
},
"headers": {
"User-Agent": "HttpRunner/${get_httprunner_version()}"
}
},
"extract": {
"session_foo2": "body.args.foo2"
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.args.sum_v", 3]},
{"less_than": ["body.args.sum_v", "${sum_two(2, 2)}"]}
]
})
"request": {
"method": "GET",
"url": "/get",
"params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"},
"headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"},
},
"extract": {"session_foo2": "body.args.foo2"},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.args.sum_v", 3]},
{"less_than": ["body.args.sum_v", "${sum_two(2, 2)}"]},
],
}
),
]
if __name__ == '__main__':
TestCaseRequestMethodsValidateWithFunctions().run()
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()

View File

@@ -1,99 +1,85 @@
# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
class TestCaseRequestMethodsValidateWithVariables(TestCaseRunner):
config = TestsConfig(**{
"name": "request methods testcase: validate with variables",
"variables": {
"foo1": "session_bar1"
},
"base_url": "https://postman-echo.com",
"verify": False
})
class TestCaseValidateWithVariables(unittest.TestCase):
config = TestsConfig(
**{
"name": "request methods testcase: validate with variables",
"variables": {"foo1": "session_bar1"},
"base_url": "https://postman-echo.com",
"verify": False,
"path": "examples/postman_echo/request_methods/validate_with_variables_test.py",
}
)
teststeps = [
TestStep(**{
"name": "get with params",
"variables": {
"foo1": "bar1",
"foo2": "session_bar2"
},
"request": {
"method": "GET",
"url": "/get",
"params": {
"foo1": "$foo1",
"foo2": "$foo2"
TestStep(
**{
"name": "get with params",
"variables": {"foo1": "bar1", "foo2": "session_bar2"},
"request": {
"method": "GET",
"url": "/get",
"params": {"foo1": "$foo1", "foo2": "$foo2"},
"headers": {"User-Agent": "HttpRunner/3.0"},
},
"headers": {
"User-Agent": "HttpRunner/3.0"
}
},
"extract": {
"session_foo2": "body.args.foo2"
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.args.foo1", "session_bar1"]},
{"eq": ["body.args.foo1", "$foo1"]},
{"eq": ["body.args.foo2", "session_bar2"]},
{"eq": ["body.args.foo2", "$foo2"]}
]
}),
TestStep(**{
"name": "post raw text",
"variables": {
"foo1": "hello world",
"foo3": "$session_foo2"
},
"request": {
"method": "POST",
"url": "/post",
"data": "This is expected to be sent back as part of response body: $foo1-$foo3.",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "text/plain"
}
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": [
"body.data",
"This is expected to be sent back as part of response body: session_bar1-session_bar2."
]},
{"eq": [
"body.data",
"This is expected to be sent back as part of response body: $foo1-$foo3."
]},
]
}),
TestStep(**{
"name": "post form data",
"variables": {
"foo1": "session_bar1",
"foo2": "bar2"
},
"request": {
"method": "POST",
"url": "/post",
"data": "foo1=$foo1&foo2=$foo2",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "application/x-www-form-urlencoded"
}
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.form.foo1", "session_bar1"]},
{"eq": ["body.form.foo1", "$foo1"]},
{"eq": ["body.form.foo2", "bar2"]},
{"eq": ["body.form.foo2", "$foo2"]}
]
})
"extract": {"session_foo2": "body.args.foo2"},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.args.foo1", "$foo1"]},
{"eq": ["body.args.foo2", "$foo2"]},
],
}
),
TestStep(
**{
"name": "post raw text",
"variables": {"foo1": "hello world", "foo3": "$session_foo2"},
"request": {
"method": "POST",
"url": "/post",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "text/plain",
},
"data": "This is expected to be sent back as part of response body: $foo1-$foo3.",
},
"validate": [
{"eq": ["status_code", 200]},
{
"eq": [
"body.data",
"This is expected to be sent back as part of response body: session_bar1-$foo3.",
]
},
],
}
),
TestStep(
**{
"name": "post form data",
"variables": {"foo1": "bar1", "foo2": "bar2"},
"request": {
"method": "POST",
"url": "/post",
"headers": {
"User-Agent": "HttpRunner/3.0",
"Content-Type": "application/x-www-form-urlencoded",
},
"data": "foo1=$foo1&foo2=$foo2",
},
"validate": [
{"eq": ["status_code", 200]},
{"eq": ["body.form.foo1", "$foo1"]},
{"eq": ["body.form.foo2", "$foo2"]},
],
}
),
]
if __name__ == '__main__':
runner = TestCaseRequestMethodsValidateWithVariables().run()
print(runner.step_datas)
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()

View File

@@ -75,7 +75,7 @@ class HttpRunner(object):
testcase.config.variables.update(project_meta.variables)
testcase.config.functions.update(project_meta.functions)
test_runner = TestCaseRunner().init(testcase)
test_runner = TestCaseRunner(testcase.config, testcase.teststeps)
TestSequense = type("TestSequense", (unittest.TestCase,), {})
test_method = _add_test(test_runner)

View File

@@ -3,14 +3,17 @@ import os
import jinja2
from loguru import logger
from httprunner.new_loader import load_testcase_file
from httprunner import exceptions
from httprunner.new_loader import load_testcase_file, load_folder_files
__TMPL__ = """# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest
__TMPL__ = """
from httprunner.runner import TestCaseRunner
from httprunner.schema import TestsConfig, TestStep
class {{ class_name }}(TestCaseRunner):
class {{ class_name }}(unittest.TestCase):
config = TestsConfig(**{{ config }})
teststeps = [
@@ -19,31 +22,50 @@ class {{ class_name }}(TestCaseRunner):
{% endfor %}
]
def test_start(self):
TestCaseRunner(self.config, self.teststeps).run()
if __name__ == '__main__':
{{ class_name }}().run()
"""
def make_testcase(path: str) -> str:
testcase = load_testcase_file(path)
def make_testcase(testcase_path: str) -> str:
testcase = load_testcase_file(testcase_path)
template = jinja2.Template(__TMPL__)
raw_file_name, _ = os.path.splitext(os.path.basename(path))
raw_file_name, _ = os.path.splitext(os.path.basename(testcase_path))
# convert title case, e.g. request_with_variables => RequestWithVariables
name_in_title_case = raw_file_name.title().replace("_", "")
testcase_dir = os.path.dirname(testcase_path)
testcase_python_path = os.path.join(testcase_dir, f"{raw_file_name}_test.py")
config = testcase["config"]
config["path"] = testcase_python_path
data = {
"class_name": f"TestCase{name_in_title_case}",
"config": testcase["config"],
"config": 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
def make(tests_path: str) -> list:
testcases = []
if os.path.isdir(tests_path):
files_list = load_folder_files(tests_path)
testcases.extend(files_list)
elif os.path.isfile(tests_path):
testcases.append(tests_path)
else:
raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}")
return [
make_testcase(testcase_path)
for testcase_path in testcases
]

21
httprunner/make_test.py Normal file
View File

@@ -0,0 +1,21 @@
import unittest
from httprunner.make import make_testcase, make
class TestLoader(unittest.TestCase):
def test_make_testcase(self):
path = "examples/postman_echo/request_methods/request_with_variables.yml"
testcase_python_path = make_testcase(path)
self.assertEqual(
testcase_python_path,
"examples/postman_echo/request_methods/request_with_variables_test.py"
)
def test_make_testcase_folder(self):
path = "examples/postman_echo/request_methods/"
testcase_python_list = make(path)
self.assertIn(
"examples/postman_echo/request_methods/request_with_functions_test.py",
testcase_python_list
)

View File

@@ -1,12 +1,14 @@
import importlib
import io
import json
import os
import sys
import types
import yaml
from loguru import logger
from httprunner import builtin
from httprunner import builtin, utils
from httprunner import exceptions
from httprunner.schema import TestCase
@@ -64,6 +66,47 @@ def load_testcase_file(testcase_file):
return testcase_content
def load_dot_env_file(dot_env_path):
""" load .env file.
Args:
dot_env_path (str): .env file path
Returns:
dict: environment variables mapping
{
"UserName": "debugtalk",
"Password": "123456",
"PROJECT_KEY": "ABCDEFGH"
}
Raises:
exceptions.FileFormatError: If .env file format is invalid.
"""
if not os.path.isfile(dot_env_path):
return {}
logger.info(f"Loading environment variables from {dot_env_path}")
env_variables_mapping = {}
with io.open(dot_env_path, "r", encoding="utf-8") as fp:
for line in fp:
# maxsplit=1
if "=" in line:
variable, value = line.split("=", 1)
elif ":" in line:
variable, value = line.split(":", 1)
else:
raise exceptions.FileFormatError(".env format error")
env_variables_mapping[variable.strip()] = value.strip()
utils.set_os_environ(env_variables_mapping)
return env_variables_mapping
def load_folder_files(folder_path, recursive=True):
""" load folder path, return all files endswith yml/yaml/json in list.
@@ -133,3 +176,169 @@ def load_builtin_functions():
""" load builtin module functions
"""
return load_module_functions(builtin)
def locate_file(start_path, file_name):
""" locate filename and return absolute file path.
searching will be recursive upward until current working directory or system root dir.
Args:
file_name (str): target locate file name
start_path (str): start locating path, maybe file path or directory path
Returns:
str: located file path. None if file not found.
Raises:
exceptions.FileNotFound: If failed to locate file.
"""
if os.path.isfile(start_path):
start_dir_path = os.path.dirname(start_path)
elif os.path.isdir(start_path):
start_dir_path = start_path
else:
raise exceptions.FileNotFound(f"invalid path: {start_path}")
file_path = os.path.join(start_dir_path, file_name)
if os.path.isfile(file_path):
return os.path.abspath(file_path)
# current working directory
if os.path.abspath(start_dir_path) == os.getcwd():
raise exceptions.FileNotFound(f"{file_name} not found in {start_path}")
# system root dir
# Windows, e.g. 'E:\\'
# Linux/Darwin, '/'
parent_dir = os.path.dirname(start_dir_path)
if parent_dir == start_dir_path:
raise exceptions.FileNotFound(f"{file_name} not found in {start_path}")
# locate recursive upward
return locate_file(parent_dir, file_name)
def locate_debugtalk_py(start_path):
""" locate debugtalk.py file
Args:
start_path (str): start locating path,
maybe testcase file path or directory path
Returns:
str: debugtalk.py file path, None if not found
"""
try:
# locate debugtalk.py file.
debugtalk_path = locate_file(start_path, "debugtalk.py")
except exceptions.FileNotFound:
debugtalk_path = None
return debugtalk_path
def init_project_working_directory(test_path):
""" this should be called at startup
run test file:
run_path -> load_cases -> load_project_data -> init_project_working_directory
or run passed in data structure:
run -> init_project_working_directory
Args:
test_path: specified testfile path
Returns:
(str, str): debugtalk.py path, project_working_directory
"""
def prepare_path(path):
if not os.path.exists(path):
err_msg = f"path not exist: {path}"
logger.error(err_msg)
raise exceptions.FileNotFound(err_msg)
if not os.path.isabs(path):
path = os.path.join(os.getcwd(), path)
return path
test_path = prepare_path(test_path)
# locate debugtalk.py file
debugtalk_path = locate_debugtalk_py(test_path)
global project_working_directory
if debugtalk_path:
# The folder contains debugtalk.py will be treated as PWD.
project_working_directory = os.path.dirname(debugtalk_path)
else:
# debugtalk.py not found, use os.getcwd() as PWD.
project_working_directory = os.getcwd()
# add PWD to sys.path
sys.path.insert(0, project_working_directory)
return debugtalk_path, project_working_directory
def load_debugtalk_functions():
""" load project debugtalk.py module functions
debugtalk.py should be located in project working directory.
Returns:
dict: debugtalk module functions mapping
{
"func1_name": func1,
"func2_name": func2
}
"""
# load debugtalk.py module
imported_module = importlib.import_module("debugtalk")
return load_module_functions(imported_module)
def load_project_data(test_path: str, dot_env_path: str = None):
""" load api, testcases, .env, debugtalk.py functions.
api/testcases folder is relative to project_working_directory
Args:
test_path (str): test file/folder path, locate pwd from this path.
dot_env_path (str): specified .env file path
Returns:
dict: project loaded api/testcases definitions,
environments and debugtalk.py functions.
"""
debugtalk_path, project_working_directory = init_project_working_directory(
test_path
)
project_meta = {}
# load .env file
# NOTICE:
# environment variable maybe loaded in debugtalk.py
# thus .env file should be loaded before loading debugtalk.py
dot_env_path = dot_env_path or os.path.join(project_working_directory, ".env")
project_meta["env"] = load_dot_env_file(dot_env_path)
if debugtalk_path:
# load debugtalk.py functions
debugtalk_functions = load_debugtalk_functions()
else:
debugtalk_functions = {}
# locate PWD and load debugtalk.py functions
project_meta["PWD"] = project_working_directory
project_meta["functions"] = debugtalk_functions
project_meta["test_path"] = os.path.abspath(test_path)[
len(project_working_directory) + 1 :
]
return project_meta

View File

@@ -2,38 +2,30 @@ from typing import List, Dict
from loguru import logger
from httprunner import utils
from httprunner import utils, exceptions
from httprunner.client import HttpSession
from httprunner.exceptions import ValidationFailure, ParamsError
from httprunner.new_loader import load_project_data
from httprunner.parser import build_url, parse_data, parse_variables_mapping
from httprunner.response import ResponseObject
from httprunner.schema import (
TestsConfig,
TestStep,
VariablesMapping,
TestCase,
StepData,
)
class TestCaseRunner(object):
config: TestsConfig = {}
teststeps: List[TestStep] = []
session: HttpSession = None
step_datas: List[StepData] = []
validation_results: Dict = {}
session_variables: Dict = {}
success: bool = True # indicate testcase execution result
def init(self, testcase: TestCase) -> "TestCaseRunner":
self.config = testcase.config
self.teststeps = testcase.teststeps
return self
def with_session(self, s: HttpSession) -> "TestCaseRunner":
self.session = s
return self
def __init__(self, config: TestsConfig, teststeps: List[TestStep], session: HttpSession = None):
self.config = config
self.teststeps = teststeps
self.session = session
self.step_datas: List[StepData] = []
self.validation_results: Dict = {}
self.session_variables: Dict = {}
self.success: bool = True # indicate testcase execution result
def with_variables(self, **variables: VariablesMapping) -> "TestCaseRunner":
self.config.variables.update(variables)
@@ -142,8 +134,14 @@ class TestCaseRunner(object):
self.step_datas.append(step_data)
return step_data.export
def test_start(self):
def run(self):
"""main entrance"""
if not self.config.path:
raise exceptions.ParamsError("config path missed!")
project_data = load_project_data(self.config.path)
self.config.functions = project_data["functions"]
self.step_datas.clear()
self.session_variables.clear()
for step in self.teststeps:
@@ -162,10 +160,6 @@ class TestCaseRunner(object):
return self
def run(self):
"""main entrance alias for test_start"""
return self.test_start()
def get_export_variables(self):
export_vars_mapping = {}
for var_name in self.config.export:

View File

@@ -40,6 +40,7 @@ class TestsConfig(BaseModel):
setup_hooks: Hook = []
teardown_hooks: Hook = []
export: Export = []
path: Text = None
class Request(BaseModel):