Merge pull request #499 from HttpRunner/fix_output

Release 2.0.2
This commit is contained in:
debugtalk
2019-01-25 19:07:39 +08:00
committed by GitHub
7 changed files with 90 additions and 83 deletions
+21 -7
View File
@@ -1,15 +1,29 @@
# Release History # Release History
## 2.0.1 (2019.01.18) ## 2.0.2 (2019-01-21)
Bugfixes: **Bugfixes**
- override current teststep variables with former testcase output variables; - each teststeps in one testcase share the same session
- make compatible with testcase name is empty; - fix duplicate API definition output
- skip undefined variable when parsing string content;
- add request method in report.
## 2.0.0 (2019.01.01) **Improvements**
- display result from hook functions in DEBUG level log
- change log level of "Variables & Output" to INFO
- print Invalid testcase path or testcases
- print testcase output in INFO level log
## 2.0.1 (2019-01-18)
**Bugfixes**
- override current teststep variables with former testcase output variables
- make compatible with testcase name is empty
- skip undefined variable when parsing string content
- add back request method in report
## 2.0.0 (2019-01-01)
- Massive Refactor and Simplification - Massive Refactor and Simplification
- Redesign testcase structure - Redesign testcase structure
+1 -1
View File
@@ -1,7 +1,7 @@
__title__ = 'HttpRunner' __title__ = 'HttpRunner'
__description__ = 'One-stop solution for HTTP(S) testing.' __description__ = 'One-stop solution for HTTP(S) testing.'
__url__ = 'https://github.com/HttpRunner/HttpRunner' __url__ = 'https://github.com/HttpRunner/HttpRunner'
__version__ = '2.0.1' __version__ = '2.0.2'
__author__ = 'debugtalk' __author__ = 'debugtalk'
__author_email__ = 'mail@debugtalk.com' __author_email__ = 'mail@debugtalk.com'
__license__ = 'Apache-2.0' __license__ = 'Apache-2.0'
+2 -5
View File
@@ -145,10 +145,7 @@ class HttpRunner(object):
summary["success"] &= testcase_summary["success"] summary["success"] &= testcase_summary["success"]
testcase_summary["name"] = testcase.config.get("name") testcase_summary["name"] = testcase.config.get("name")
testcase_summary["in_out"] = utils.get_testcase_io(testcase)
in_out = utils.get_testcase_io(testcase)
utils.print_io(in_out)
testcase_summary["in_out"] = in_out
report.aggregate_stat(summary["stat"]["teststeps"], testcase_summary["stat"]) report.aggregate_stat(summary["stat"]["teststeps"], testcase_summary["stat"])
report.aggregate_stat(summary["time"], testcase_summary["time"]) report.aggregate_stat(summary["time"], testcase_summary["time"])
@@ -233,7 +230,7 @@ class HttpRunner(object):
elif validator.is_testcases(path_or_tests): elif validator.is_testcases(path_or_tests):
return self.run_tests(path_or_tests) return self.run_tests(path_or_tests)
else: else:
raise exceptions.ParamsError("invalid testcase path or testcases.") raise exceptions.ParamsError("Invalid testcase path or testcases: {}".format(path_or_tests))
@property @property
def summary(self): def summary(self):
+2
View File
@@ -169,6 +169,8 @@ class HttpSession(requests.Session):
:param cert: (optional) :param cert: (optional)
if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
""" """
self.init_meta_data()
# record test name # record test name
self.meta_data["name"] = name self.meta_data["name"] = name
+13 -7
View File
@@ -613,17 +613,23 @@ def load_api_folder(api_folder_path):
if isinstance(api_items, list): if isinstance(api_items, list):
for api_item in api_items: for api_item in api_items:
key, api_dict = api_item.popitem() key, api_dict = api_item.popitem()
api_id = api_dict.get("id") api_id = api_dict.get("id") or api_dict.get("def") or api_dict.get("name")
if api_id in api_definition_mapping: if key != "api" or not api_id:
logger.log_warning("API definition duplicated: {}".format(api_id)) raise exceptions.ParamsError(
"Invalid API defined in {}".format(api_file_path))
api_definition_mapping[api_id] = api_dict if api_id in api_definition_mapping:
raise exceptions.ParamsError(
"Duplicated API ({}) defined in {}".format(api_id, api_file_path))
else:
api_definition_mapping[api_id] = api_dict
elif isinstance(api_items, dict): elif isinstance(api_items, dict):
if api_file_path in api_definition_mapping: if api_file_path in api_definition_mapping:
logger.log_warning("API definition duplicated: {}".format(api_file_path)) raise exceptions.ParamsError(
"Duplicated API defined: {}".format(api_file_path))
api_definition_mapping[api_file_path] = api_items else:
api_definition_mapping[api_file_path] = api_items
return api_definition_mapping return api_definition_mapping
+13 -13
View File
@@ -140,10 +140,14 @@ class Runner(object):
# format 1 # format 1
# {"var": "${func()}"} # {"var": "${func()}"}
var_name, hook_content = list(action.items())[0] var_name, hook_content = list(action.items())[0]
logger.log_debug("assignment with hook: {} = {}".format(var_name, hook_content)) hook_content_eval = self.session_context.eval_content(hook_content)
logger.log_debug(
"assignment with hook: {} = {} => {}".format(
var_name, hook_content, hook_content_eval
)
)
self.session_context.update_test_variables( self.session_context.update_test_variables(
var_name, var_name, hook_content_eval
self.session_context.eval_content(hook_content)
) )
else: else:
# format 2 # format 2
@@ -282,11 +286,9 @@ class Runner(object):
""" """
self.meta_datas = [] self.meta_datas = []
config = testcase_dict.get("config", {}) config = testcase_dict.get("config", {})
base_url = config.get("base_url")
# each testcase should have individual session. # each teststeps in one testcase (YAML/JSON) share the same session.
http_client_session = self.http_client_session.__class__(base_url) test_runner = Runner(config, self.functions, self.http_client_session)
test_runner = Runner(config, self.functions, http_client_session)
tests = testcase_dict.get("teststeps", []) tests = testcase_dict.get("teststeps", [])
@@ -309,7 +311,9 @@ class Runner(object):
_meta_datas = test_runner.meta_datas _meta_datas = test_runner.meta_datas
self.meta_datas.append(_meta_datas) self.meta_datas.append(_meta_datas)
self.session_context.update_session_variables(test_runner.extract_sessions()) self.session_context.update_session_variables(
test_runner.extract_output(test_runner.output)
)
def run_test(self, test_dict): def run_test(self, test_dict):
""" run single teststep of testcase. """ run single teststep of testcase.
@@ -360,11 +364,6 @@ class Runner(object):
finally: finally:
self.meta_datas = self.__get_test_data() self.meta_datas = self.__get_test_data()
def extract_sessions(self):
"""
"""
return self.extract_output(self.output)
def extract_output(self, output_variables_list): def extract_output(self, output_variables_list):
""" extract output variables """ extract output variables
""" """
@@ -381,4 +380,5 @@ class Runner(object):
output[variable] = variables_mapping[variable] output[variable] = variables_mapping[variable]
utils.print_info(output)
return output return output
+38 -50
View File
@@ -433,13 +433,12 @@ def extend_variables(raw_variables, override_variables):
def get_testcase_io(testcase): def get_testcase_io(testcase):
""" get testcase input(variables) and output. """ get and print testcase input(variables) and output.
Args: Args:
testcase (unittest.suite.TestSuite): corresponding to one YAML/JSON file, it has been set two attributes: testcase (unittest.suite.TestSuite): corresponding to one YAML/JSON file, it has been set two attributes:
config: parsed config block config: parsed config block
runner: initialized runner.Runner() with config runner: initialized runner.Runner() with config
Returns: Returns:
dict: input(variables) and output mapping. dict: input(variables) and output mapping.
@@ -447,72 +446,61 @@ def get_testcase_io(testcase):
test_runner = testcase.runner test_runner = testcase.runner
variables = testcase.config.get("variables", {}) variables = testcase.config.get("variables", {})
output_list = testcase.config.get("output", []) output_list = testcase.config.get("output", [])
output_mapping = test_runner.extract_output(output_list)
return { return {
"in": variables, "in": variables,
"out": test_runner.extract_output(output_list) "out": output_mapping
} }
def print_io(in_out): def print_info(info_mapping):
""" print input(variables) and output. """ print info in mapping.
Args: Args:
in_out (dict): input(variables) and output mapping. info_mapping (dict): input(variables) or output mapping.
Examples: Examples:
>>> in_out = { >>> info_mapping = {
"in": { "var_a": "hello",
"var_a": "hello", "var_b": "world"
"var_b": "world"
},
"out": {
"status_code": 500
}
} }
>>> print_io(in_out) >>> info_mapping = {
================== Variables & Output ================== "status_code": 500
Type | Variable : Value }
------ | ---------------- : --------------------------- >>> print_info(info_mapping)
Var | var_a : hello ==================== Output ====================
Var | var_b : world Key : Value
---------------- : ----------------------------
Out | status_code : 500 var_a : hello
-------------------------------------------------------- var_b : world
------------------------------------------------
""" """
content_format = "{:<6} | {:<16} : {:<}\n" if not info_mapping:
content = "\n================== Variables & Output ==================\n" return
content += content_format.format("Type", "Variable", "Value")
content += content_format.format("-" * 6, "-" * 16, "-" * 27)
def prepare_content(var_type, in_out): content_format = "{:<16} : {:<}\n"
content = "" content = "\n==================== Output ====================\n"
for variable, value in in_out.items(): content += content_format.format("Variable", "Value")
if isinstance(value, (tuple, collections.deque)): content += content_format.format("-" * 16, "-" * 29)
continue
elif isinstance(value, (dict, list)):
value = json.dumps(value)
if is_py2: for key, value in info_mapping.items():
if isinstance(variable, unicode): if isinstance(value, (tuple, collections.deque)):
variable = variable.encode("utf-8") continue
if isinstance(value, unicode): elif isinstance(value, (dict, list)):
value = value.encode("utf-8") value = json.dumps(value)
content += content_format.format(var_type, variable, value) if is_py2:
if isinstance(key, unicode):
key = key.encode("utf-8")
if isinstance(value, unicode):
value = value.encode("utf-8")
return content content += content_format.format(key, value)
_in = in_out["in"] content += "-" * 48 + "\n"
_out = in_out["out"] logger.log_info(content)
content += prepare_content("Var", _in)
content += "\n"
content += prepare_content("Out", _out)
content += "-" * 56 + "\n"
logger.log_debug(content)
def create_scaffold(project_name): def create_scaffold(project_name):