diff --git a/examples/postman_echo/request_methods/request_with_functions_test.py b/examples/postman_echo/request_methods/request_with_functions_test.py index b8f333bb..ff7180aa 100644 --- a/examples/postman_echo/request_methods/request_with_functions_test.py +++ b/examples/postman_echo/request_methods/request_with_functions_test.py @@ -1,87 +1,69 @@ # NOTICE: Generated By HttpRunner. DO NOT EDIT! # FROM: examples/postman_echo/request_methods/request_with_functions.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithFunctions(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase with functions", - "variables": {"foo1": "session_bar1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/request_with_functions_test.py", - } + config = ( + Config("request methods testcase with functions") + .variables(**{"foo1": "session_bar1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "variables": { - "foo1": "bar1", - "foo2": "session_bar2", - "sum_v": "${sum_two(1, 2)}", - }, - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}, - "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, - }, - "extract": {"session_foo2": "body.args.foo2"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.foo1", "session_bar1"]}, - {"eq": ["body.args.sum_v", "3"]}, - {"eq": ["body.args.foo2", "session_bar2"]}, - ], - } + Step( + RunRequest("get with params") + .with_variables( + **{"foo1": "bar1", "foo2": "session_bar2", "sum_v": "${sum_two(1, 2)}"} + ) + .get("/get") + .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}) + .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"}) + .extract() + .with_jmespath("body.args.foo2", "session_foo2") + .validate() + .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") ), - TStep( - **{ - "name": "post raw text", - "variables": {"foo1": "hello world", "foo3": "$session_foo2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/${get_httprunner_version()}", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body: $foo1-$foo3.", - }, - "validate": [ - {"eq": ["status_code", 200]}, - { - "eq": [ - "body.data", - "This is expected to be sent back as part of response body: session_bar1-session_bar2.", - ] - }, - ], - } + Step( + RunRequest("post raw text") + .with_variables(**{"foo1": "hello world", "foo3": "$session_foo2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/${get_httprunner_version()}", + "Content-Type": "text/plain", + } + ) + .with_data( + "This is expected to be sent back as part of response body: $foo1-$foo3." + ) + .validate() + .assert_equal("status_code", 200) + .assert_equal( + "body.data", + "This is expected to be sent back as part of response body: session_bar1-session_bar2.", + ) ), - TStep( - **{ - "name": "post form data", - "variables": {"foo1": "bar1", "foo2": "bar2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/${get_httprunner_version()}", - "Content-Type": "application/x-www-form-urlencoded", - }, - "data": "foo1=$foo1&foo2=$foo2", - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.form.foo1", "session_bar1"]}, - {"eq": ["body.form.foo2", "bar2"]}, - ], - } + Step( + RunRequest("post form data") + .with_variables(**{"foo1": "bar1", "foo2": "bar2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/${get_httprunner_version()}", + "Content-Type": "application/x-www-form-urlencoded", + } + ) + .with_data("foo1=$foo1&foo2=$foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.form.foo1", "session_bar1") + .assert_equal("body.form.foo2", "bar2") ), ] diff --git a/httprunner/cli.py b/httprunner/cli.py index 762ae2a7..5297074d 100644 --- a/httprunner/cli.py +++ b/httprunner/cli.py @@ -23,14 +23,9 @@ def main_run(extra_args): # keep compatibility with v2 extra_args = ensure_cli_args(extra_args) - chain_style = False tests_path_list = [] extra_args_new = [] for item in extra_args: - if item == "--chain-style": - chain_style = True - continue - if not os.path.exists(item): # item is not file/folder path extra_args_new.append(item) @@ -43,7 +38,7 @@ def main_run(extra_args): logger.error(f"No valid testcase path in cli arguments: {extra_args}") sys.exit(1) - testcase_path_list = main_make(tests_path_list, chain_style=chain_style) + testcase_path_list = main_make(tests_path_list) if not testcase_path_list: logger.error("No valid testcases found, exit 1.") sys.exit(1) @@ -115,7 +110,7 @@ def main(): elif sys.argv[1] == "har2case": main_har2case(args) elif sys.argv[1] == "make": - main_make(args.testcase_path, chain_style=args.chain_style) + main_make(args.testcase_path) def main_hrun_alias(): diff --git a/httprunner/make.py b/httprunner/make.py index a2ca8066..94dfa6aa 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -29,35 +29,6 @@ __TEMPLATE__ = jinja2.Template( import os import sys -sys.path.insert(0, os.getcwd()) -{% endif %} -from httprunner import HttpRunner, TConfig, TStep -{% for import_str in imports_list %} -{{ import_str }} -{% endfor %} - -class {{ class_name }}(HttpRunner): - config = TConfig(**{{ config }}) - - teststeps = [ - {% for teststep in teststeps %} - TStep(**{{ teststep }}), - {% endfor %} - ] - -if __name__ == "__main__": - {{ class_name }}().test_start() - -""" -) - -__TEMPLATE_CHAIN_STYLE__ = jinja2.Template( - """# NOTICE: Generated By HttpRunner. DO NOT EDIT! -# FROM: {{ testcase_path }} -{% if imports_list %} -import os -import sys - sys.path.insert(0, os.getcwd()) {% endif %} from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase @@ -231,7 +202,7 @@ def make_teststep_chain_style(teststep: Dict) -> Text: if teststep.get("request"): step_info += make_request_chain_style(teststep["request"]) elif teststep.get("testcase"): - testcase = teststep["testcase"].replace("CLS_LB(", "").replace(")CLS_RB", "") + testcase = teststep["testcase"] call_ref_testcase = f".call({testcase})" step_info += call_ref_testcase @@ -248,19 +219,21 @@ def make_teststep_chain_style(teststep: Dict) -> Text: validator = uniform_validator(v) assert_method = validator["assert"] check = validator["check"] + if '"' in check: + # e.g. body."user-agent" => 'body."user-agent"' + check = f"'{check}'" + else: + check = f'"{check}"' expect = validator["expect"] if isinstance(expect, Text): expect = f'"{expect}"' - step_info += f'.assert_{assert_method}("{check}", {expect})' + step_info += f'.assert_{assert_method}({check}, {expect})' return f"Step({step_info})" def __make_testcase( - testcase: Dict, - dir_path: Text = None, - ref_flag: bool = False, - chain_style: bool = False, + testcase: Dict, dir_path: Text = None, ref_flag: bool = False, ) -> NoReturn: """convert valid testcase dict to pytest file path""" # ensure compatibility with testcase format v2 @@ -309,7 +282,7 @@ def __make_testcase( ref_testcase_python_path, ref_testcase_cls_name = convert_testcase_path( ref_testcase_path ) - teststep["testcase"] = f"CLS_LB({ref_testcase_cls_name})CLS_RB" + teststep["testcase"] = ref_testcase_cls_name # prepare import ref testcase ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1 :] @@ -323,19 +296,12 @@ def __make_testcase( "testcase_path": __ensure_cwd_relative(testcase_path), "class_name": f"TestCase{testcase_cls_name}", "imports_list": imports_list, - } - - if chain_style: - data["config_chain_style"] = make_config_chain_style(config) - data["teststeps_chain_style"] = [ + "config_chain_style": make_config_chain_style(config), + "teststeps_chain_style": [ make_teststep_chain_style(step) for step in teststeps - ] - content = __TEMPLATE_CHAIN_STYLE__.render(data) - else: - data["config"] = config - data["teststeps"] = teststeps - content = __TEMPLATE__.render(data) - content = content.replace("'CLS_LB(", "").replace(")CLS_RB'", "") + ], + } + content = __TEMPLATE__.render(data) with open(testcase_python_path, "w", encoding="utf-8") as f: f.write(content) @@ -348,7 +314,7 @@ def __make_testcase( make_files_cache_set.add(__ensure_cwd_relative(testcase_python_path)) -def __make_testsuite(testsuite: Dict, chain_style: bool = False) -> NoReturn: +def __make_testsuite(testsuite: Dict) -> NoReturn: """convert valid testsuite dict to pytest folder with testcases""" # validate testsuite format load_testsuite(testsuite) @@ -393,12 +359,10 @@ def __make_testsuite(testsuite: Dict, chain_style: bool = False) -> NoReturn: testcase_dict["config"]["variables"].update(testsuite_variables) # make testcase - __make_testcase(testcase_dict, testsuite_dir, chain_style=chain_style) + __make_testcase(testcase_dict, testsuite_dir) -def __make( - tests_path: Text, ref_flag: bool = False, chain_style: bool = False -) -> NoReturn: +def __make(tests_path: Text, ref_flag: bool = False) -> NoReturn: """ make testcase(s) with testcase/testsuite/folder absolute path generated pytest file path will be cached in make_files_cache_set @@ -432,16 +396,14 @@ def __make( # testcase if "teststeps" in test_content: try: - __make_testcase( - test_content, ref_flag=ref_flag, chain_style=chain_style - ) + __make_testcase(test_content, ref_flag=ref_flag) except exceptions.TestCaseFormatError: continue # testsuite elif "testcases" in test_content: try: - __make_testsuite(test_content, chain_style=chain_style) + __make_testsuite(test_content) except exceptions.TestSuiteFormatError: continue @@ -452,12 +414,12 @@ def __make( ) -def main_make(tests_paths: List[Text], chain_style: bool = False) -> List[Text]: +def main_make(tests_paths: List[Text]) -> List[Text]: for tests_path in tests_paths: if not os.path.isabs(tests_path): tests_path = os.path.join(os.getcwd(), tests_path) - __make(tests_path, chain_style=chain_style) + __make(tests_path) testcase_path_list = list(make_files_cache_set) __format_pytest_with_black(testcase_path_list) @@ -473,11 +435,5 @@ def init_make_parser(subparsers): parser.add_argument( "testcase_path", nargs="*", help="Specify YAML/JSON testcase file/folder path" ) - parser.add_argument( - "--chain-style", - dest="chain_style", - action="store_true", - help="Convert pytest files in chain-style.", - ) return parser diff --git a/httprunner/runner.py b/httprunner/runner.py index b2c9060f..b42aef3a 100644 --- a/httprunner/runner.py +++ b/httprunner/runner.py @@ -2,7 +2,7 @@ import os import time import uuid from datetime import datetime -from typing import List, Dict, Text, NoReturn, Union +from typing import List, Dict, Text, NoReturn try: import allure @@ -35,8 +35,8 @@ from httprunner.schema import ( class HttpRunner(object): - config: Union[TConfig, Config] - teststeps: List[Union[TStep, Step]] + config: Config + teststeps: List[Step] success: bool = True # indicate testcase execution result __config: TConfig @@ -53,21 +53,10 @@ class HttpRunner(object): __log_path: Text = "" def __init_tests__(self) -> NoReturn: - if isinstance(self.config, TConfig): - self.__config = self.config - elif isinstance(self.config, Config): - self.__config = self.config.perform() - else: - raise exceptions.TestCaseFormatError(f"config type error: {self.config}") - + self.__config = self.config.perform() self.__teststeps = [] for step in self.teststeps: - if isinstance(step, TStep): - self.__teststeps.append(step) - elif isinstance(step, Step): - self.__teststeps.append(step.perform()) - else: - raise exceptions.TestCaseFormatError(f"step type error: {step}") + self.__teststeps.append(step.perform()) def with_project_meta(self, project_meta: ProjectMeta) -> "HttpRunner": self.__project_meta = project_meta diff --git a/httprunner/scaffold.py b/httprunner/scaffold.py index 9fe48471..bf48893f 100644 --- a/httprunner/scaffold.py +++ b/httprunner/scaffold.py @@ -66,7 +66,7 @@ teststeps: validate: - eq: ["status_code", 200] - eq: ["body.args.foo1", "session_bar1"] - - eq: ["body.args.sum_v", 3] + - eq: ["body.args.sum_v", "3"] - eq: ["body.args.foo2", "session_bar2"] - name: post raw text diff --git a/httprunner/testcase.py b/httprunner/testcase.py index 1f772a2a..175e331b 100644 --- a/httprunner/testcase.py +++ b/httprunner/testcase.py @@ -189,6 +189,7 @@ class RunTestCase(object): def call(self, testcase: Callable): self.__t_step.testcase = testcase + return self def perform(self) -> TStep: return self.__t_step diff --git a/tests/make_test.py b/tests/make_test.py index 703f5f10..5bb5fbb1 100644 --- a/tests/make_test.py +++ b/tests/make_test.py @@ -43,7 +43,7 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( content, ) self.assertIn( - '"testcase": RequestWithFunctions,', content, + '.call(RequestWithFunctions)', content, ) def test_make_testcase_folder(self):