feat: implement step setup/teardown hooks

This commit is contained in:
debugtalk
2020-06-07 16:38:59 +08:00
parent 5cc5e5be28
commit 31f5cfa9df
3 changed files with 67 additions and 6 deletions

View File

@@ -1,5 +1,11 @@
# Release History # Release History
## 3.0.10 (2020-06-07)
**Added**
- feat: implement step setup/teardown hooks
## 3.0.9 (2020-06-07) ## 3.0.9 (2020-06-07)
**Fixed** **Fixed**

View File

@@ -15,7 +15,7 @@ FunctionsMapping = Dict[Text, Callable]
Headers = Dict[Text, Text] Headers = Dict[Text, Text]
Cookies = Dict[Text, Text] Cookies = Dict[Text, Text]
Verify = bool Verify = bool
Hook = List[Text] Hooks = Union[List[Text], Dict[Text, Text]]
Export = List[Text] Export = List[Text]
Validators = List[Dict] Validators = List[Dict]
Env = Dict[Text, Any] Env = Dict[Text, Any]
@@ -37,8 +37,8 @@ class TConfig(BaseModel):
base_url: BaseUrl = "" base_url: BaseUrl = ""
# Text: prepare variables in debugtalk.py, ${gen_variables()} # Text: prepare variables in debugtalk.py, ${gen_variables()}
variables: Union[VariablesMapping, Text] = {} variables: Union[VariablesMapping, Text] = {}
setup_hooks: Hook = [] # setup_hooks: Hooks = []
teardown_hooks: Hook = [] # teardown_hooks: Hooks = []
export: Export = [] export: Export = []
path: Text = None path: Text = None
@@ -64,8 +64,8 @@ class TStep(BaseModel):
request: Union[TRequest, None] = None request: Union[TRequest, None] = None
testcase: Union[Text, Callable, None] = None testcase: Union[Text, Callable, None] = None
variables: VariablesMapping = {} variables: VariablesMapping = {}
setup_hooks: Hook = [] setup_hooks: Hooks = []
teardown_hooks: Hook = [] teardown_hooks: Hooks = []
# used to extract request's response field # used to extract request's response field
extract: VariablesMapping = {} extract: VariablesMapping = {}
# used to export session variables from referenced testcase # used to export session variables from referenced testcase

View File

@@ -2,7 +2,7 @@ import os
import time import time
import uuid import uuid
from datetime import datetime from datetime import datetime
from typing import List, Dict, Text, NoReturn from typing import List, Dict, Text, NoReturn, Union
try: try:
import allure import allure
@@ -31,6 +31,7 @@ from httprunner.models import (
TestCaseInOut, TestCaseInOut,
ProjectMeta, ProjectMeta,
TestCase, TestCase,
Hooks,
) )
@@ -86,6 +87,50 @@ class HttpRunner(object):
self.__export = export self.__export = export
return self return self
def __call_hooks(
self, hooks: Hooks, step_variables: VariablesMapping, hook_type: Text,
) -> NoReturn:
""" call hook actions.
Args:
hooks: each action in actions list maybe in two format.
format1 (dict): assignment, the value returned by hook function will be assigned to variable.
{"var": "${func()}"}
format2 (str): only call hook functions.
${func()}
step_variables: current step variables to call hook, include two special variables
request: parsed request dict
response: ResponseObject for current response
hook_type: setup/teardown
"""
logger.debug(f"call {hook_type} hook actions.")
if isinstance(hooks, Dict):
# format 1: {"var": "${func()}"}
for var_name, hook_content in hooks.items():
hook_content_eval = parse_data(
hook_content, step_variables, self.__project_meta.functions
)
logger.debug(
f"call hook function: {hook_content}, got value: {hook_content_eval}"
)
logger.debug(f"assign variable: {var_name} = {hook_content_eval}")
step_variables[var_name] = hook_content_eval
elif isinstance(hooks, List):
# format 2: ["${func()}"]
for hook in hooks:
logger.debug(f"call hook function: {hook}")
parse_data(hook, step_variables, self.__project_meta.functions)
else:
logger.warning(f"Invalid hooks format: {hooks}")
def __run_step_request(self, step: TStep) -> StepData: def __run_step_request(self, step: TStep) -> StepData:
"""run teststep: request""" """run teststep: request"""
step_data = StepData(name=step.name) step_data = StepData(name=step.name)
@@ -101,6 +146,11 @@ class HttpRunner(object):
"HRUN-Request-ID", "HRUN-Request-ID",
f"HRUN-{self.__case_id}-{str(int(time.time() * 1000))[-6:]}", f"HRUN-{self.__case_id}-{str(int(time.time() * 1000))[-6:]}",
) )
step.variables["request"] = parsed_request_dict
# setup hooks
if step.setup_hooks:
self.__call_hooks(step.setup_hooks, step.variables, "setup")
# prepare arguments # prepare arguments
method = parsed_request_dict.pop("method") method = parsed_request_dict.pop("method")
@@ -112,6 +162,11 @@ class HttpRunner(object):
# request # request
resp = self.__session.request(method, url, **parsed_request_dict) resp = self.__session.request(method, url, **parsed_request_dict)
resp_obj = ResponseObject(resp) resp_obj = ResponseObject(resp)
step.variables["response"] = resp_obj
# teardown hooks
if step.teardown_hooks:
self.__call_hooks(step.teardown_hooks, step.variables, "teardown")
def log_req_resp_details(): def log_req_resp_details():
err_msg = "\n{} DETAILED REQUEST & RESPONSE {}\n".format("*" * 32, "*" * 32) err_msg = "\n{} DETAILED REQUEST & RESPONSE {}\n".format("*" * 32, "*" * 32)