refactor: HttpRunner config & teststeps

This commit is contained in:
debugtalk
2020-06-01 14:27:52 +08:00
parent 0905350e99
commit 2b30a1337b
4 changed files with 78 additions and 60 deletions

View File

@@ -2,10 +2,9 @@ import uuid
from typing import List
import pytest
from httprunner import Config, Step
from loguru import logger
from httprunner.schema import TConfig, TStep
@pytest.fixture(scope="session", autouse=True)
def session_fixture(request):
@@ -33,8 +32,8 @@ def session_fixture(request):
@pytest.fixture(scope="function", autouse=True)
def testcase_fixture(request):
"""setup and teardown each testcase"""
config: TConfig = request.cls.config
teststeps: List[TStep] = request.cls.teststeps
config: Config = request.cls.config
teststeps: List[Step] = request.cls.teststeps
logger.debug(f"setup testcase fixture: {config.name} - {request.module.__name__}")

View File

@@ -10,10 +10,9 @@ class TestCaseRequestWithFunctions(HttpRunner):
.variables(foo1="session_bar1")
.base_url("https://postman-echo.com")
.verify(False)
.path(
.set_path(
"examples/postman_echo/request_methods/request_with_functions_test.py"
)
.init()
)
teststeps = [
@@ -29,8 +28,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
.assert_equal("status_code", 200)
.assert_equal("body.args.foo1", "session_bar1")
.assert_equal("body.args.sum_v", "3")
.assert_equal("body.args.foo2", "session_bar2")
.init(),
.assert_equal("body.args.foo2", "session_bar2"),
Step("post raw text")
.with_variables(foo1="hello world", foo3="$session_foo2")
.run_request(
@@ -50,8 +48,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
.assert_equal(
"body.data",
"This is expected to be sent back as part of response body: session_bar1-session_bar2.",
)
.init(),
),
Step("post form data")
.with_variables(**{"foo1": "bar1", "foo2": "bar2"})
.run_request(
@@ -67,8 +64,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
)
.assert_equal("status_code", 200)
.assert_equal("body.form.foo1", "session_bar1")
.assert_equal("body.form.foo2", "bar2")
.init(),
.assert_equal("body.form.foo2", "bar2"),
]

View File

@@ -20,6 +20,7 @@ from httprunner.ext.uploader import prepare_upload_step
from httprunner.loader import load_project_meta, load_testcase_file
from httprunner.parser import build_url, parse_data, parse_variables_mapping
from httprunner.response import ResponseObject
from httprunner.testcase import Config, Step
from httprunner.schema import (
TConfig,
TStep,
@@ -34,10 +35,12 @@ from httprunner.schema import (
class HttpRunner(object):
config: TConfig
teststeps: List[TStep]
config: Config
teststeps: List[Step]
success: bool = True # indicate testcase execution result
__config: TConfig
__teststeps: List[TStep]
__project_meta: ProjectMeta = None
__case_id: Text = ""
__step_datas: List[StepData] = None
@@ -84,7 +87,7 @@ class HttpRunner(object):
# prepare arguments
method = parsed_request_dict.pop("method")
url_path = parsed_request_dict.pop("url")
url = build_url(self.config.base_url, url_path)
url = build_url(self.__config.base_url, url_path)
parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {})
# request
@@ -220,21 +223,23 @@ class HttpRunner(object):
>>> HttpRunner().with_project_meta(project_meta).run_testcase(testcase_obj)
"""
self.config = testcase.config
self.teststeps = testcase.teststeps
self.__config = testcase.config
self.__teststeps = testcase.teststeps
# prepare
self.__project_meta = self.__project_meta or load_project_meta(self.config.path)
self.__parse_config(self.config)
self.__project_meta = self.__project_meta or load_project_meta(
self.__config.path
)
self.__parse_config(self.__config)
self.__start_at = time.time()
self.__step_datas: List[StepData] = []
self.__session = self.__session or HttpSession()
self.__session_variables = {}
# run teststeps
for step in self.teststeps:
for step in self.__teststeps:
# update with config variables
step.variables.update(self.config.variables)
step.variables.update(self.__config.variables)
# update with session variables extracted from pre step
step.variables.update(self.__session_variables)
# parse variables
@@ -267,7 +272,9 @@ class HttpRunner(object):
>>> TestCaseRequestWithFunctions().run()
"""
testcase_obj = TestCase(config=self.config, teststeps=self.teststeps)
self.__config = self.config.perform()
self.__teststeps = [step.perform() for step in self.teststeps]
testcase_obj = TestCase(config=self.__config, teststeps=self.__teststeps)
return self.run_testcase(testcase_obj)
def get_step_datas(self) -> List[StepData]:
@@ -275,7 +282,7 @@ class HttpRunner(object):
def get_export_variables(self) -> Dict:
export_vars_mapping = {}
for var_name in self.config.export:
for var_name in self.__config.export:
if var_name not in self.__session_variables:
raise ParamsError(
f"failed to export variable {var_name} from session variables {self.__session_variables}"
@@ -290,7 +297,7 @@ class HttpRunner(object):
start_at_timestamp = self.__start_at
start_at_iso_format = datetime.utcfromtimestamp(start_at_timestamp).isoformat()
return TestCaseSummary(
name=self.config.name,
name=self.__config.name,
success=self.success,
case_id=self.__case_id,
time=TestCaseTime(
@@ -299,7 +306,7 @@ class HttpRunner(object):
duration=self.__duration,
),
in_out=TestCaseInOut(
vars=self.config.variables, export=self.get_export_variables()
vars=self.__config.variables, export=self.get_export_variables()
),
log=self.__log_path,
step_datas=self.__step_datas,
@@ -307,7 +314,11 @@ class HttpRunner(object):
def test_start(self) -> "HttpRunner":
"""main entrance, discovered by pytest"""
self.__project_meta = self.__project_meta or load_project_meta(self.config.path)
self.__config = self.config.perform()
self.__teststeps = [step.perform() for step in self.teststeps]
self.__project_meta = self.__project_meta or load_project_meta(
self.__config.path
)
self.__case_id = self.__case_id or str(uuid.uuid4())
self.__log_path = self.__log_path or os.path.join(
self.__project_meta.PWD, "logs", f"{self.__case_id}.run.log"
@@ -315,24 +326,24 @@ class HttpRunner(object):
log_handler = logger.add(self.__log_path, level="DEBUG")
# parse config name
variables = self.config.variables
variables = self.__config.variables
variables.update(self.__session_variables)
self.config.name = parse_data(
self.config.name, variables, self.__project_meta.functions
self.__config.name = parse_data(
self.__config.name, variables, self.__project_meta.functions
)
if USE_ALLURE:
# update allure report meta
allure.dynamic.title(self.config.name)
allure.dynamic.title(self.__config.name)
allure.dynamic.description(f"TestCase ID: {self.__case_id}")
logger.info(
f"Start to run testcase: {self.config.name}, TestCase ID: {self.__case_id}"
f"Start to run testcase: {self.__config.name}, TestCase ID: {self.__case_id}"
)
try:
return self.run_testcase(
TestCase(config=self.config, teststeps=self.teststeps)
TestCase(config=self.__config, teststeps=self.__teststeps)
)
finally:
logger.remove(log_handler)

View File

@@ -1,4 +1,4 @@
from typing import Text, Any
from typing import Text, Any, Dict
from httprunner.schema import (
TConfig,
@@ -16,6 +16,14 @@ class Config(object):
self.__verify = False
self.__path = ""
@property
def name(self):
return self.__name
@property
def path(self):
return self.__path
def variables(self, **variables) -> "Config":
self.__variables.update(variables)
return self
@@ -28,11 +36,11 @@ class Config(object):
self.__verify = verify
return self
def path(self, path: Text) -> "Config":
def set_path(self, path: Text) -> "Config":
self.__path = path
return self
def init(self) -> TConfig:
def perform(self) -> TConfig:
return TConfig(
name=self.__name,
base_url=self.__base_url,
@@ -42,7 +50,7 @@ class Config(object):
)
class RequestOptionalArgs(object):
class RequestWithOptionalArgs(object):
def __init__(self, method: MethodEnum, url: Text):
self.__method = method
self.__url = url
@@ -54,31 +62,31 @@ class RequestOptionalArgs(object):
self.__allow_redirects = True
self.__verify = False
def with_params(self, **params) -> "RequestOptionalArgs":
def with_params(self, **params) -> "RequestWithOptionalArgs":
self.__params.update(params)
return self
def with_headers(self, **headers) -> "RequestOptionalArgs":
def with_headers(self, **headers) -> "RequestWithOptionalArgs":
self.__headers.update(headers)
return self
def with_cookies(self, **cookies) -> "RequestOptionalArgs":
def with_cookies(self, **cookies) -> "RequestWithOptionalArgs":
self.__cookies.update(cookies)
return self
def with_data(self, data) -> "RequestOptionalArgs":
def with_data(self, data) -> "RequestWithOptionalArgs":
self.__data = data
return self
def set_timeout(self, timeout: float) -> "RequestOptionalArgs":
def set_timeout(self, timeout: float) -> "RequestWithOptionalArgs":
self.__timeout = timeout
return self
def set_verify(self, verify: bool) -> "RequestOptionalArgs":
def set_verify(self, verify: bool) -> "RequestWithOptionalArgs":
self.__verify = verify
return self
def set_allow_redirects(self, allow_redirects: bool) -> "RequestOptionalArgs":
def set_allow_redirects(self, allow_redirects: bool) -> "RequestWithOptionalArgs":
self.__allow_redirects = allow_redirects
return self
@@ -97,30 +105,30 @@ class RequestOptionalArgs(object):
class Request(object):
def get(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.GET, url)
def get(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.GET, url)
def post(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.POST, url)
def post(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.POST, url)
def put(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.PUT, url)
def put(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.PUT, url)
def head(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.HEAD, url)
def head(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.HEAD, url)
def delete(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.DELETE, url)
def delete(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.DELETE, url)
def options(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.OPTIONS, url)
def options(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.OPTIONS, url)
def patch(self, url: Text) -> RequestOptionalArgs:
return RequestOptionalArgs(MethodEnum.PATCH, url)
def patch(self, url: Text) -> RequestWithOptionalArgs:
return RequestWithOptionalArgs(MethodEnum.PATCH, url)
class Step(object):
def __init__(self, name):
def __init__(self, name: Text):
self.__name = name
self.__variables = {}
self.__request = None
@@ -131,7 +139,11 @@ class Step(object):
self.__variables.update(variables)
return self
def run_request(self, req_obj: RequestOptionalArgs) -> "Step":
@property
def request(self) -> TRequest:
return self.__request
def run_request(self, req_obj: RequestWithOptionalArgs) -> "Step":
self.__request = req_obj.perform()
return self
@@ -151,7 +163,7 @@ class Step(object):
self.__validators.append({"lt": [jmes_path, expected_value]})
return self
def init(self) -> TStep:
def perform(self) -> TStep:
return TStep(
name=self.__name,
variables=self.__variables,