call HttpRunner class with testsets data structure other than path

This commit is contained in:
httprunner
2018-04-17 21:41:02 +08:00
parent efaf4365b2
commit a92f382571
5 changed files with 233 additions and 27 deletions

View File

@@ -152,30 +152,34 @@ class TaskSuite(unittest.TestSuite):
""" create task suite with specified testcase path. """ create task suite with specified testcase path.
each task suite may include one or several test suite. each task suite may include one or several test suite.
""" """
def __init__(self, path, mapping=None, http_client_session=None): def __init__(self, testsets, mapping=None, http_client_session=None):
""" """
@params @params
path: path could be in several type testsets (dict/list): testset or list of testset
- absolute/relative file path testset_dict
- absolute/relative folder path or
- list/set container with file(s) and/or folder(s) [
(dict) mapping: testset_dict_1,
testset_dict_2,
{
"name": "desc1",
"config": {},
"api": {},
"testcases": [testcase11, testcase12]
}
]
mapping (dict):
passed in variables mapping, it will override variables in config block passed in variables mapping, it will override variables in config block
""" """
super(TaskSuite, self).__init__() super(TaskSuite, self).__init__()
mapping = mapping or {} mapping = mapping or {}
if not isinstance(path, list):
# absolute/relative file/folder path
path = [path]
# remove duplicate path
path = set(path)
testsets = testcase.load_testcases_by_path(path)
if not testsets: if not testsets:
raise exception.TestcaseNotFound raise exception.TestcaseNotFound
if isinstance(testsets, dict):
testsets = [testsets]
self.suite_list = [] self.suite_list = []
for testset in testsets: for testset in testsets:
suite = TestSuite(testset, mapping, http_client_session) suite = TestSuite(testset, mapping, http_client_session)
@@ -187,6 +191,18 @@ class TaskSuite(unittest.TestSuite):
return self.suite_list return self.suite_list
def init_task_suite(path_or_testsets, mapping=None, http_client_session=None):
""" initialize task suite
"""
if not testcase.is_testsets(path_or_testsets):
testsets = testcase.load_testcases_by_path(path_or_testsets)
else:
testsets = path_or_testsets
mapping = mapping or {}
return TaskSuite(testsets, mapping, http_client_session)
class HttpRunner(object): class HttpRunner(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
@@ -198,16 +214,25 @@ class HttpRunner(object):
kwargs.setdefault("resultclass", HtmlTestResult) kwargs.setdefault("resultclass", HtmlTestResult)
self.runner = unittest.TextTestRunner(**kwargs) self.runner = unittest.TextTestRunner(**kwargs)
def run(self, path, mapping=None): def run(self, path_or_testsets, mapping=None):
""" start to run specified testset file with varaibles mapping """ start to run test with varaibles mapping
@param (str) path: @param path_or_testsets: YAML/JSON testset file path or testset list
YAML/JSON testset file path path: path could be in several type
- absolute/relative file path
- absolute/relative folder path
- list/set container with file(s) and/or folder(s)
testsets: testset or list of testset
- (dict) testset_dict
- (list) list of testset_dict
[
testset_dict_1,
testset_dict_2
]
@param (dict) mapping: @param (dict) mapping:
if mapping specified, it will override variables in config block if mapping specified, it will override variables in config block
""" """
try: try:
mapping = mapping or {} task_suite = init_task_suite(path_or_testsets, mapping)
task_suite = TaskSuite(path, mapping)
except exception.TestcaseNotFound: except exception.TestcaseNotFound:
logger.log_error("Testcases not found in {}".format(path)) logger.log_error("Testcases not found in {}".format(path))
sys.exit(1) sys.exit(1)
@@ -238,9 +263,8 @@ class HttpRunner(object):
class LocustTask(object): class LocustTask(object):
def __init__(self, path, locust_client, mapping=None): def __init__(self, path_or_testsets, locust_client, mapping=None):
mapping = mapping or {} self.task_suite = init_task_suite(path_or_testsets, mapping, locust_client)
self.task_suite = TaskSuite(path, mapping, locust_client)
def run(self): def run(self):
for suite in self.task_suite: for suite in self.task_suite:

View File

@@ -417,6 +417,46 @@ def extend_test_api(test_block_dict):
test_extracors test_extracors
) )
def is_testset(data_structure):
""" check if data_structure is a testset
testset should always be in the following data structure:
{
"name": "desc1",
"config": {},
"api": {},
"testcases": [testcase11, testcase12]
}
"""
if not isinstance(data_structure, dict):
return False
if "name" not in data_structure or "testcases" not in data_structure:
return False
if not isinstance(data_structure["testcases"], list):
return False
return True
def is_testsets(data_structure):
""" check if data_structure is testset or testsets
testsets should always be in the following data structure:
testset_dict
or
[
testset_dict_1,
testset_dict_2
]
"""
if not isinstance(data_structure, list):
return is_testset(data_structure)
for item in data_structure:
if not is_testset(item):
return False
return True
def load_test_file(file_path): def load_test_file(file_path):
""" load testset file, get testset data structure. """ load testset file, get testset data structure.
@param file_path: absolute valid testset file path @param file_path: absolute valid testset file path
@@ -467,7 +507,9 @@ def load_test_file(file_path):
testset["api"][func_name] = api_info testset["api"][func_name] = api_info
else: else:
logger.log_warning("unexpected block: {}. block should only be config or test.".format(key)) logger.log_warning(
"unexpected block: {}. block should only be 'config', 'test' or 'api'.".format(key)
)
return testset return testset

View File

@@ -9,6 +9,53 @@ class TestHttpRunner(ApiServerUnittest):
def setUp(self): def setUp(self):
self.testset_path = "tests/data/demo_testset_cli.yml" self.testset_path = "tests/data/demo_testset_cli.yml"
self.testset = {
'name': 'testset description',
'config': {
'path': 'docs/data/demo-quickstart-2.yml',
'name': 'testset description',
'request': {
'base_url': '',
'headers': {'User-Agent': 'python-requests/2.18.4'}
},
'variables': [],
'output': ['token']
},
'api': {},
'testcases': [
{
'name': '/api/get-token',
'request': {
'url': 'http://127.0.0.1:5000/api/get-token',
'method': 'POST',
'headers': {'Content-Type': 'application/json', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios', 'user_agent': 'iOS/10.3'},
'json': {'sign': '958a05393efef0ac7c0fb80a7eac45e24fd40c27'}
},
'extract': [
{'token': 'content.token'}
],
'validate': [
{'eq': ['status_code', 200]},
{'eq': ['headers.Content-Type', 'application/json']},
{'eq': ['content.success', True]}
]
},
{
'name': '/api/users/1000',
'request': {
'url': 'http://127.0.0.1:5000/api/users/1000',
'method': 'POST',
'headers': {'Content-Type': 'application/json', 'device_sn': 'FwgRiO7CNA50DSU','token': '$token'}, 'json': {'name': 'user1', 'password': '123456'}
},
'validate': [
{'eq': ['status_code', 201]},
{'eq': ['headers.Content-Type', 'application/json']},
{'eq': ['content.success', True]},
{'eq': ['content.msg', 'user created successfully.']}
]
}
]
}
self.reset_all() self.reset_all()
def reset_all(self): def reset_all(self):
@@ -35,3 +82,19 @@ class TestHttpRunner(ApiServerUnittest):
runner.gen_html_report(html_report_name=output_folder_name) runner.gen_html_report(html_report_name=output_folder_name)
report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name) report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name)
shutil.rmtree(report_save_dir) shutil.rmtree(report_save_dir)
def test_run_testsets(self):
testsets = [self.testset]
runner = HttpRunner().run(testsets)
summary = runner.summary
self.assertTrue(summary["success"])
self.assertEqual(summary["stat"]["testsRun"], 2)
self.assertIn("records", summary)
def test_run_testset(self):
testsets = self.testset
runner = HttpRunner().run(testsets)
summary = runner.summary
self.assertTrue(summary["success"])
self.assertEqual(summary["stat"]["testsRun"], 2)
self.assertIn("records", summary)

View File

@@ -24,9 +24,57 @@ class TestTask(ApiServerUnittest):
self.assertIsInstance(testcase, task.TestCase) self.assertIsInstance(testcase, task.TestCase)
def test_create_task(self): def test_create_task(self):
testcase_file_path = os.path.join(os.getcwd(), 'tests/data/demo_testset_variables.yml') testsets = [
task_suite = task.TaskSuite(testcase_file_path) {
self.assertEqual(task_suite.countTestCases(), 3) 'name': 'testset description',
'config': {
'path': 'docs/data/demo-quickstart-2.yml',
'name': 'testset description',
'request': {
'base_url': '',
'headers': {'User-Agent': 'python-requests/2.18.4'}
},
'variables': [],
'output': ['token']
},
'api': {},
'testcases': [
{
'name': '/api/get-token',
'request': {
'url': 'http://127.0.0.1:5000/api/get-token',
'method': 'POST',
'headers': {'Content-Type': 'application/json', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios', 'user_agent': 'iOS/10.3'},
'json': {'sign': '958a05393efef0ac7c0fb80a7eac45e24fd40c27'}
},
'extract': [
{'token': 'content.token'}
],
'validate': [
{'eq': ['status_code', 200]},
{'eq': ['headers.Content-Type', 'application/json']},
{'eq': ['content.success', True]}
]
},
{
'name': '/api/users/1000',
'request': {
'url': 'http://127.0.0.1:5000/api/users/1000',
'method': 'POST',
'headers': {'Content-Type': 'application/json', 'device_sn': 'FwgRiO7CNA50DSU','token': '$token'}, 'json': {'name': 'user1', 'password': '123456'}
},
'validate': [
{'eq': ['status_code', 201]},
{'eq': ['headers.Content-Type', 'application/json']},
{'eq': ['content.success', True]},
{'eq': ['content.msg', 'user created successfully.']}
]
}
]
}
]
task_suite = task.TaskSuite(testsets)
self.assertEqual(task_suite.countTestCases(), 2)
for suite in task_suite: for suite in task_suite:
for testcase in suite: for testcase in suite:
self.assertIsInstance(testcase, task.TestCase) self.assertIsInstance(testcase, task.TestCase)

View File

@@ -738,3 +738,32 @@ class TestcaseParserUnittest(unittest.TestCase):
{"var3": "val3"}, {"var3": "val3"},
merged_extractors merged_extractors
) )
def test_is_testsets(self):
data_structure = "path/to/file"
self.assertFalse(testcase.is_testsets(data_structure))
data_structure = ["path/to/file1", "path/to/file2"]
self.assertFalse(testcase.is_testsets(data_structure))
data_structure = {
"name": "desc1",
"config": {},
"api": {},
"testcases": ["testcase11", "testcase12"]
}
self.assertTrue(data_structure)
data_structure = [
{
"name": "desc1",
"config": {},
"api": {},
"testcases": ["testcase11", "testcase12"]
},
{
"name": "desc2",
"config": {},
"api": {},
"testcases": ["testcase21", "testcase22"]
}
]
self.assertTrue(data_structure)