mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 19:39:44 +08:00
refactor lib function interface
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
__title__ = 'HttpRunner'
|
||||
__description__ = 'One-stop solution for HTTP(S) testing.'
|
||||
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
||||
__version__ = '1.3.8.beta.3'
|
||||
__version__ = '1.3.9'
|
||||
__author__ = 'debugtalk'
|
||||
__author_email__ = 'mail@debugtalk.com'
|
||||
__license__ = 'MIT'
|
||||
|
||||
@@ -26,6 +26,9 @@ def main_hrun():
|
||||
parser.add_argument(
|
||||
'testset_paths', nargs='*',
|
||||
help="testset file path")
|
||||
parser.add_argument(
|
||||
'--no-html-report', action='store_true', default=False,
|
||||
help="do not generate html report.")
|
||||
parser.add_argument(
|
||||
'--html-report-name',
|
||||
help="specify html report name, only effective when generating html report.")
|
||||
@@ -78,13 +81,17 @@ def main_hrun():
|
||||
create_scaffold(project_path)
|
||||
exit(0)
|
||||
|
||||
result = HttpRunner(args.testset_paths, failfast=args.failfast).run(
|
||||
html_report_name=args.html_report_name,
|
||||
html_report_template=args.html_report_template
|
||||
)
|
||||
runner = HttpRunner(failfast=args.failfast).run(args.testset_paths)
|
||||
|
||||
print_output(result["output"])
|
||||
return 0 if result["success"] else 1
|
||||
if not args.no_html_report:
|
||||
runner.gen_html_report(
|
||||
html_report_name=args.html_report_name,
|
||||
html_report_template=args.html_report_template
|
||||
)
|
||||
|
||||
summary = runner.summary
|
||||
print_output(summary["output"])
|
||||
return 0 if summary["success"] else 1
|
||||
|
||||
def main_locust():
|
||||
""" Performance test with locust: parse command line options and run commands.
|
||||
|
||||
@@ -53,9 +53,56 @@ def get_summary(result):
|
||||
'duration': result.duration
|
||||
}
|
||||
summary["records"] = result.records
|
||||
else:
|
||||
summary["records"] = []
|
||||
|
||||
return summary
|
||||
|
||||
def render_html_report(summary, html_report_name=None, html_report_template=None):
|
||||
""" render html report with specified report name and template
|
||||
if html_report_name is not specified, use current datetime
|
||||
if html_report_template is not specified, use default report template
|
||||
"""
|
||||
if not html_report_template:
|
||||
html_report_template = os.path.join(
|
||||
os.path.abspath(os.path.dirname(__file__)),
|
||||
"templates",
|
||||
"default_report_template.html"
|
||||
)
|
||||
logger.log_debug("No html report template specified, use default.")
|
||||
else:
|
||||
logger.log_info("render with html report template: {}".format(html_report_template))
|
||||
|
||||
logger.log_info("Start to render Html report ...")
|
||||
logger.log_debug("render data: {}".format(summary))
|
||||
|
||||
report_dir_path = os.path.join(os.getcwd(), "reports")
|
||||
start_datetime = summary["time"]["start_at"].strftime('%Y-%m-%d-%H-%M-%S')
|
||||
if html_report_name:
|
||||
summary["html_report_name"] = html_report_name
|
||||
report_dir_path = os.path.join(report_dir_path, html_report_name)
|
||||
html_report_name += "-{}.html".format(start_datetime)
|
||||
else:
|
||||
summary["html_report_name"] = ""
|
||||
html_report_name = "{}.html".format(start_datetime)
|
||||
|
||||
if not os.path.isdir(report_dir_path):
|
||||
os.makedirs(report_dir_path)
|
||||
|
||||
for record in summary.get("records"):
|
||||
record["meta_data"] = make_json_serializable(record["meta_data"])
|
||||
|
||||
with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
|
||||
template_content = fp_r.read()
|
||||
report_path = os.path.join(report_dir_path, html_report_name)
|
||||
with io.open(report_path, 'w', encoding='utf-8') as fp_w:
|
||||
rendered_content = Template(template_content).render(summary)
|
||||
fp_w.write(rendered_content)
|
||||
|
||||
logger.log_info("Generated Html report: {}".format(report_path))
|
||||
|
||||
return report_path
|
||||
|
||||
def make_json_serializable(raw_json):
|
||||
serializable_json = {}
|
||||
for key, value in raw_json.items():
|
||||
@@ -86,12 +133,6 @@ class HtmlTestResult(unittest.TextTestResult):
|
||||
def __init__(self, stream, descriptions, verbosity):
|
||||
super(HtmlTestResult, self).__init__(stream, descriptions, verbosity)
|
||||
self.records = []
|
||||
self.default_report_template_path = os.path.join(
|
||||
os.path.abspath(os.path.dirname(__file__)),
|
||||
"templates",
|
||||
"default_report_template.html"
|
||||
)
|
||||
self.report_path = None
|
||||
|
||||
def _record_test(self, test, status, attachment=''):
|
||||
self.records.append({
|
||||
@@ -99,7 +140,7 @@ class HtmlTestResult(unittest.TextTestResult):
|
||||
'status': status,
|
||||
'response_time_ms': test.meta_data.get("response_time(ms)", 0),
|
||||
'attachment': attachment,
|
||||
"meta_data": make_json_serializable(test.meta_data)
|
||||
"meta_data": test.meta_data
|
||||
})
|
||||
|
||||
def startTestRun(self):
|
||||
@@ -143,46 +184,3 @@ class HtmlTestResult(unittest.TextTestResult):
|
||||
@property
|
||||
def duration(self):
|
||||
return time.time() - self.start_at
|
||||
|
||||
@property
|
||||
def summary(self):
|
||||
return get_summary(self)
|
||||
|
||||
def render_html_report(self, html_report_name=None, html_report_template=None):
|
||||
""" render html report with specified report name and template
|
||||
if html_report_name is not specified, use current datetime
|
||||
if html_report_template is not specified, use default report template
|
||||
"""
|
||||
if not html_report_template:
|
||||
html_report_template = self.default_report_template_path
|
||||
logger.log_debug("No html report template specified, use default.")
|
||||
else:
|
||||
logger.log_info("render with html report template: {}".format(html_report_template))
|
||||
|
||||
summary = self.summary
|
||||
logger.log_info("Start to render Html report ...")
|
||||
logger.log_debug("render data: {}".format(summary))
|
||||
|
||||
report_dir_path = os.path.join(os.getcwd(), "reports")
|
||||
start_datetime = summary["time"]["start_at"].strftime('%Y-%m-%d-%H-%M-%S')
|
||||
if html_report_name:
|
||||
summary["html_report_name"] = html_report_name
|
||||
report_dir_path = os.path.join(report_dir_path, html_report_name)
|
||||
html_report_name += "-{}.html".format(start_datetime)
|
||||
else:
|
||||
summary["html_report_name"] = ""
|
||||
html_report_name = "{}.html".format(start_datetime)
|
||||
|
||||
if not os.path.isdir(report_dir_path):
|
||||
os.makedirs(report_dir_path)
|
||||
|
||||
with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
|
||||
template_content = fp_r.read()
|
||||
report_path = os.path.join(report_dir_path, html_report_name)
|
||||
with io.open(report_path, 'w', encoding='utf-8') as fp_w:
|
||||
rendered_content = Template(template_content).render(summary)
|
||||
fp_w.write(rendered_content)
|
||||
|
||||
logger.log_info("Generated Html report: {}".format(report_path))
|
||||
|
||||
return report_path
|
||||
|
||||
@@ -6,7 +6,7 @@ import unittest
|
||||
|
||||
from httprunner import exception, logger, runner, testcase, utils
|
||||
from httprunner.compat import is_py3
|
||||
from httprunner.report import HtmlTestResult, get_summary
|
||||
from httprunner.report import HtmlTestResult, get_summary, render_html_report
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
@@ -189,58 +189,51 @@ class TaskSuite(unittest.TestSuite):
|
||||
|
||||
class HttpRunner(object):
|
||||
|
||||
def __init__(self, path, gen_html_report=True, **kwargs):
|
||||
""" initialize HttpRunner with specified testset file path and test runner
|
||||
@param (str) path:
|
||||
YAML/JSON testset file path
|
||||
@param (boolean) gen_html_report:
|
||||
True: use HtmlTestResult and generate html report
|
||||
False: use TextTestResult and do not generate report file
|
||||
@param (dict) kwargs:
|
||||
key-value arguments used to initialize TextTestRunner
|
||||
- failfast: False/True, stop the test run on the first error or failure.
|
||||
def __init__(self, **kwargs):
|
||||
""" initialize test runner
|
||||
@param (dict) kwargs: key-value arguments used to initialize TextTestRunner
|
||||
- resultclass: HtmlTestResult or TextTestResult
|
||||
- failfast: False/True, stop the test run on the first error or failure.
|
||||
"""
|
||||
self.path = path
|
||||
|
||||
self.gen_html_report = gen_html_report
|
||||
if self.gen_html_report:
|
||||
kwargs["resultclass"] = HtmlTestResult
|
||||
|
||||
kwargs.setdefault("resultclass", HtmlTestResult)
|
||||
self.runner = unittest.TextTestRunner(**kwargs)
|
||||
|
||||
def run(self, mapping=None, html_report_name=None, html_report_template=None):
|
||||
""" start to run suite
|
||||
def run(self, path, mapping=None):
|
||||
""" start to run specified testset file with varaibles mapping
|
||||
@param (str) path:
|
||||
YAML/JSON testset file path
|
||||
@param (dict) mapping:
|
||||
if mapping specified, it will override variables in config block
|
||||
@param (str) html_report_name:
|
||||
output html report file name
|
||||
@param (str) html_report_template:
|
||||
report template file path, template should be in Jinja2 format
|
||||
"""
|
||||
try:
|
||||
mapping = mapping or {}
|
||||
task_suite = TaskSuite(self.path, mapping)
|
||||
task_suite = TaskSuite(path, mapping)
|
||||
except exception.TestcaseNotFound:
|
||||
logger.log_error("Testcases not found in {}".format(self.path))
|
||||
logger.log_error("Testcases not found in {}".format(path))
|
||||
sys.exit(1)
|
||||
|
||||
result = self.runner.run(task_suite)
|
||||
self.summary = get_summary(result)
|
||||
|
||||
output = []
|
||||
for task in task_suite.tasks:
|
||||
output.extend(task.output)
|
||||
|
||||
if self.gen_html_report:
|
||||
summary = result.summary
|
||||
summary["report_path"] = result.render_html_report(
|
||||
html_report_name,
|
||||
html_report_template
|
||||
)
|
||||
else:
|
||||
summary = get_summary(result)
|
||||
self.summary["output"] = output
|
||||
return self
|
||||
|
||||
summary["output"] = output
|
||||
return summary
|
||||
def gen_html_report(self, html_report_name=None, html_report_template=None):
|
||||
""" generate html report and return report path
|
||||
@param (str) html_report_name:
|
||||
output html report file name
|
||||
@param (str) html_report_template:
|
||||
report template file path, template should be in Jinja2 format
|
||||
"""
|
||||
return render_html_report(
|
||||
self.summary,
|
||||
html_report_name,
|
||||
html_report_template
|
||||
)
|
||||
|
||||
|
||||
class LocustTask(object):
|
||||
|
||||
@@ -17,30 +17,21 @@ class TestHttpRunner(ApiServerUnittest):
|
||||
return self.api_client.get(url, headers=headers)
|
||||
|
||||
def test_text_run_times(self):
|
||||
kwargs = {
|
||||
"gen_html_report": False
|
||||
}
|
||||
result = HttpRunner(self.testset_path, **kwargs).run()
|
||||
self.assertEqual(result["stat"]["testsRun"], 10)
|
||||
runner = HttpRunner().run(self.testset_path)
|
||||
self.assertEqual(runner.summary["stat"]["testsRun"], 10)
|
||||
|
||||
def test_text_skip(self):
|
||||
kwargs = {
|
||||
"gen_html_report": False
|
||||
}
|
||||
result = HttpRunner(self.testset_path, **kwargs).run()
|
||||
self.assertEqual(result["stat"]["skipped"], 4)
|
||||
runner = HttpRunner().run(self.testset_path)
|
||||
self.assertEqual(runner.summary["stat"]["skipped"], 4)
|
||||
|
||||
def test_html_report(self):
|
||||
kwargs = {
|
||||
"gen_html_report": True
|
||||
}
|
||||
kwargs = {}
|
||||
output_folder_name = os.path.basename(os.path.splitext(self.testset_path)[0])
|
||||
run_kwargs = {
|
||||
"html_report_name": output_folder_name
|
||||
}
|
||||
result = HttpRunner(self.testset_path).run(**run_kwargs)
|
||||
self.assertEqual(result["stat"]["testsRun"], 10)
|
||||
self.assertEqual(result["stat"]["skipped"], 4)
|
||||
runner = HttpRunner().run(self.testset_path)
|
||||
summary = runner.summary
|
||||
self.assertEqual(summary["stat"]["testsRun"], 10)
|
||||
self.assertEqual(summary["stat"]["skipped"], 4)
|
||||
|
||||
runner.gen_html_report(html_report_name=output_folder_name)
|
||||
report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name)
|
||||
shutil.rmtree(report_save_dir)
|
||||
|
||||
@@ -77,52 +77,59 @@ class TestRunner(ApiServerUnittest):
|
||||
|
||||
def test_run_testset_hardcode(self):
|
||||
for testcase_file_path in self.testcase_file_path_list:
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
self.assertTrue(runner.summary["success"])
|
||||
|
||||
def test_run_testsets_hardcode(self):
|
||||
result = HttpRunner(self.testcase_file_path_list).run()
|
||||
self.assertTrue(result["success"])
|
||||
self.assertEqual(result["stat"]["testsRun"], 6)
|
||||
self.assertEqual(result["stat"]["successes"], 6)
|
||||
runner = HttpRunner().run(self.testcase_file_path_list)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
self.assertEqual(summary["stat"]["testsRun"], 6)
|
||||
self.assertEqual(summary["stat"]["successes"], 6)
|
||||
|
||||
def test_run_testset_template_variables(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_testset_variables.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
|
||||
def test_run_testset_template_import_functions(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_testset_template_import_functions.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
|
||||
def test_run_testsets_template_import_functions(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_testset_template_import_functions.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
|
||||
def test_run_testsets_template_lambda_functions(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_testset_template_lambda_functions.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
|
||||
def test_run_testset_layered(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_testset_layer.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
|
||||
def test_run_testset_output(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_testset_layer.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
self.assertIn("token", result["output"][0]["out"])
|
||||
self.assertEqual(len(result["output"]), 13)
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
self.assertIn("token", summary["output"][0]["out"])
|
||||
self.assertEqual(len(summary["output"]), 13)
|
||||
|
||||
def test_run_testset_with_variables_mapping(self):
|
||||
testcase_file_path = os.path.join(
|
||||
@@ -130,10 +137,11 @@ class TestRunner(ApiServerUnittest):
|
||||
variables_mapping = {
|
||||
"app_version": '2.9.7'
|
||||
}
|
||||
result = HttpRunner(testcase_file_path).run(mapping=variables_mapping)
|
||||
self.assertTrue(result["success"])
|
||||
self.assertIn("token", result["output"][0]["out"])
|
||||
self.assertEqual(len(result["output"]), 13)
|
||||
runner = HttpRunner().run(testcase_file_path, mapping=variables_mapping)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
self.assertIn("token", summary["output"][0]["out"])
|
||||
self.assertEqual(len(summary["output"]), 13)
|
||||
|
||||
def test_run_testcase_with_empty_header(self):
|
||||
testcase_file_path = os.path.join(
|
||||
@@ -163,7 +171,8 @@ class TestRunner(ApiServerUnittest):
|
||||
def test_run_testset_with_parameters(self):
|
||||
testcase_file_path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_parameters.yml')
|
||||
result = HttpRunner(testcase_file_path).run()
|
||||
self.assertTrue(result["success"])
|
||||
self.assertEqual(len(result["output"]), 3 * 2 * 2)
|
||||
self.assertEqual(result["stat"]["testsRun"], 3 * 2 * 2)
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
summary = runner.summary
|
||||
self.assertTrue(summary["success"])
|
||||
self.assertEqual(len(summary["output"]), 3 * 2 * 2)
|
||||
self.assertEqual(summary["stat"]["testsRun"], 3 * 2 * 2)
|
||||
|
||||
Reference in New Issue
Block a user