From acd85136dd23732734605c020eceff64446fd41b Mon Sep 17 00:00:00 2001 From: debugtalk Date: Sat, 2 Apr 2022 10:28:25 +0800 Subject: [PATCH] fix: run referenced testcase in python --- examples/httpbin/basic_test.py | 2 +- examples/httpbin/hooks_test.py | 2 +- examples/httpbin/load_image_test.py | 2 +- examples/httpbin/upload_test.py | 2 +- examples/httpbin/validate_test.py | 2 +- httprunner/cli.py | 2 +- httprunner/cli_test.py | 14 ++++++++-- httprunner/models.py | 17 +++++------- httprunner/response_test.py | 13 +++++----- httprunner/runner.py | 12 ++++----- httprunner/runner_test.py | 40 ----------------------------- httprunner/step_request_test.py | 16 ++++++++++++ httprunner/step_testcase.py | 28 +++++++------------- httprunner/step_testcase_test.py | 23 +++++++++++++++++ 14 files changed, 85 insertions(+), 90 deletions(-) delete mode 100644 httprunner/runner_test.py create mode 100644 httprunner/step_request_test.py create mode 100644 httprunner/step_testcase_test.py diff --git a/examples/httpbin/basic_test.py b/examples/httpbin/basic_test.py index c16102bb..eec02f1f 100644 --- a/examples/httpbin/basic_test.py +++ b/examples/httpbin/basic_test.py @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.7 +# NOTE: Generated By HttpRunner v4.0.0-alpha # FROM: basic.yml diff --git a/examples/httpbin/hooks_test.py b/examples/httpbin/hooks_test.py index ef4fce08..0a696d8f 100644 --- a/examples/httpbin/hooks_test.py +++ b/examples/httpbin/hooks_test.py @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.7 +# NOTE: Generated By HttpRunner v4.0.0-alpha # FROM: hooks.yml diff --git a/examples/httpbin/load_image_test.py b/examples/httpbin/load_image_test.py index a3827b85..d00e0e22 100644 --- a/examples/httpbin/load_image_test.py +++ b/examples/httpbin/load_image_test.py @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.7 +# NOTE: Generated By HttpRunner v4.0.0-alpha # FROM: load_image.yml diff --git a/examples/httpbin/upload_test.py b/examples/httpbin/upload_test.py index c3886e0c..f9ef8406 100644 --- a/examples/httpbin/upload_test.py +++ b/examples/httpbin/upload_test.py @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.7 +# NOTE: Generated By HttpRunner v4.0.0-alpha # FROM: upload.yml diff --git a/examples/httpbin/validate_test.py b/examples/httpbin/validate_test.py index c6ddd3f9..fe1c2b76 100644 --- a/examples/httpbin/validate_test.py +++ b/examples/httpbin/validate_test.py @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.7 +# NOTE: Generated By HttpRunner v4.0.0-alpha # FROM: validate.yml diff --git a/httprunner/cli.py b/httprunner/cli.py index d015313e..38676857 100644 --- a/httprunner/cli.py +++ b/httprunner/cli.py @@ -63,7 +63,7 @@ def main(): ) subparsers = parser.add_subparsers(help="sub-command help") - sub_parser_run = init_parser_run(subparsers) + init_parser_run(subparsers) sub_parser_make = init_make_parser(subparsers) if len(sys.argv) == 1: diff --git a/httprunner/cli_test.py b/httprunner/cli_test.py index 863ef0bd..8a95ef0f 100644 --- a/httprunner/cli_test.py +++ b/httprunner/cli_test.py @@ -5,7 +5,8 @@ import unittest import pytest -from httprunner.cli import main +from httprunner import loader +from httprunner.cli import main, main_run class TestCli(unittest.TestCase): @@ -45,8 +46,17 @@ class TestCli(unittest.TestCase): try: os.chdir(os.path.join(cwd, "examples", "postman_echo")) exit_code = pytest.main( - ["-s", "request_methods/request_with_testcase_reference_test.py",] + ["-s", "request_methods/request_with_testcase_reference_test.py"] ) self.assertEqual(exit_code, 0) finally: os.chdir(cwd) + + def test_run_testcase_with_abnormal_path(self): + loader.project_meta = None + exit_code = main_run(["examples/data/a-b.c/2 3.yml"]) + self.assertEqual(exit_code, 0) + self.assertTrue(os.path.exists("examples/data/a_b_c/__init__.py")) + self.assertTrue(os.path.exists("examples/data/debugtalk.py")) + self.assertTrue(os.path.exists("examples/data/a_b_c/T1_test.py")) + self.assertTrue(os.path.exists("examples/data/a_b_c/T2_3_test.py")) diff --git a/httprunner/models.py b/httprunner/models.py index 95d2fb30..bff6a0c7 100644 --- a/httprunner/models.py +++ b/httprunner/models.py @@ -1,11 +1,8 @@ import os from enum import Enum -from typing import Any -from typing import Dict, Text, Union, Callable -from typing import List +from typing import Any, Callable, Dict, List, Text, Union -from pydantic import BaseModel, Field -from pydantic import HttpUrl +from pydantic import BaseModel, Field, HttpUrl Name = Text Url = Text @@ -156,14 +153,14 @@ class SessionData(BaseModel): class StepData(BaseModel): """teststep data, each step maybe corresponding to one request or one testcase""" - name: Text = "" # teststep name - step_type: Text = "" # teststep type, request or testcase + name: Text = "" # teststep name + step_type: Text = "" # teststep type, request or testcase success: bool = False data: Union[SessionData, List['StepData']] = None - elapsed: float = 0.0 # teststep elapsed time - content_size: float = 0 # response content size + elapsed: float = 0.0 # teststep elapsed time + content_size: float = 0 # response content size export_vars: VariablesMapping = {} - attachment: Text = "" # teststep attachment + attachment: Text = "" # teststep attachment StepData.update_forward_refs() diff --git a/httprunner/response_test.py b/httprunner/response_test.py index 05e9cc39..8b292f46 100644 --- a/httprunner/response_test.py +++ b/httprunner/response_test.py @@ -2,6 +2,7 @@ import unittest import requests +from httprunner.parser import Parser from httprunner.response import ResponseObject @@ -18,15 +19,16 @@ class TestResponse(unittest.TestCase): ] }, ) - self.resp_obj = ResponseObject(resp) + parser = Parser(functions_mapping={ + 'get_name': lambda: 'name', + "get_num": lambda x: x + }) + self.resp_obj = ResponseObject(resp, parser) def test_extract(self): variables_mapping = { 'body': 'body' } - functions_mapping = { - 'get_name': lambda: 'name', - } extract_mapping = self.resp_obj.extract( { "var_1": "body.json.locations[0]", @@ -35,7 +37,6 @@ class TestResponse(unittest.TestCase): "var_4": "$body.json.locations[3].${get_name()}", }, variables_mapping=variables_mapping, - functions_mapping=functions_mapping, ) self.assertEqual(extract_mapping["var_1"], {"name": "Seattle", "state": "WA"}) self.assertEqual(extract_mapping["var_2"], "Olympia") @@ -62,9 +63,7 @@ class TestResponse(unittest.TestCase): def test_validate_functions(self): variables_mapping = {"index": 1} - functions_mapping = {"get_num": lambda x: x} self.resp_obj.validate( [{"eq": ["${get_num(0)}", 0]}, {"eq": ["${get_num($index)}", 1]},], variables_mapping=variables_mapping, - functions_mapping=functions_mapping, ) diff --git a/httprunner/runner.py b/httprunner/runner.py index af9b6ee7..24b40d0c 100644 --- a/httprunner/runner.py +++ b/httprunner/runner.py @@ -16,9 +16,10 @@ from loguru import logger from httprunner.client import HttpSession from httprunner.config import Config from httprunner.exceptions import ParamsError -from httprunner.loader import load_project_meta -from httprunner.models import (ProjectMeta, StepData, TConfig, TestCaseInOut, - TestCaseSummary, TestCaseTime, VariablesMapping) +from httprunner.loader import load_project_meta, load_testcase_file +from httprunner.models import (ProjectMeta, StepData, TConfig, TestCase, + TestCaseInOut, TestCaseSummary, TestCaseTime, + VariablesMapping) from httprunner.parser import Parser from httprunner.utils import merge_variables @@ -175,11 +176,9 @@ class HttpRunner(object): logger.info(f"run step end: {step.name()} <<<<<<\n") - def test_start(self, param: Dict = None): + def test_start(self, param: Dict = None) -> "HttpRunner": """main entrance, discovered by pytest""" self.__init() - log_handler = logger.add(self.__log_path, level="DEBUG") - self.__parse_config(param) if USE_ALLURE: @@ -191,6 +190,7 @@ class HttpRunner(object): f"Start to run testcase: {self.__config.name}, TestCase ID: {self.case_id}" ) + log_handler = logger.add(self.__log_path, level="DEBUG") self.__start_at = time.time() try: # run step in sequential order diff --git a/httprunner/runner_test.py b/httprunner/runner_test.py deleted file mode 100644 index ef59dcdf..00000000 --- a/httprunner/runner_test.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -import unittest - -from httprunner import loader -from httprunner.cli import main_run -from httprunner.runner import HttpRunner - - -class TestHttpRunner(unittest.TestCase): - def setUp(self): - loader.project_meta = None - self.runner = HttpRunner() - - def test_run_testcase_by_path_request_only(self): - self.runner.run_path( - "examples/postman_echo/request_methods/request_with_functions.yml" - ) - result = self.runner.get_summary() - self.assertTrue(result.success) - self.assertEqual(result.name, "request methods testcase with functions") - self.assertEqual(result.step_datas[0].name, "get with params") - self.assertEqual(len(result.step_datas), 3) - - def test_run_testcase_by_path_ref_testcase(self): - self.runner.run_path( - "examples/postman_echo/request_methods/request_with_testcase_reference.yml" - ) - result = self.runner.get_summary() - self.assertTrue(result.success) - self.assertEqual(result.name, "request methods testcase: reference testcase") - self.assertEqual(result.step_datas[0].name, "request with functions") - self.assertEqual(len(result.step_datas), 2) - - def test_run_testcase_with_abnormal_path(self): - exit_code = main_run(["examples/data/a-b.c/2 3.yml"]) - self.assertEqual(exit_code, 0) - self.assertTrue(os.path.exists("examples/data/a_b_c/__init__.py")) - self.assertTrue(os.path.exists("examples/data/debugtalk.py")) - self.assertTrue(os.path.exists("examples/data/a_b_c/T1_test.py")) - self.assertTrue(os.path.exists("examples/data/a_b_c/T2_3_test.py")) diff --git a/httprunner/step_request_test.py b/httprunner/step_request_test.py new file mode 100644 index 00000000..f6984b78 --- /dev/null +++ b/httprunner/step_request_test.py @@ -0,0 +1,16 @@ +import unittest + +from examples.postman_echo.request_methods.request_with_functions_test import TestCaseRequestWithFunctions + + +class TestRunRequest(unittest.TestCase): + + def test_run_request(self): + runner = TestCaseRequestWithFunctions().test_start() + summary = runner.get_summary() + self.assertTrue(summary.success) + self.assertEqual(summary.name, "request methods testcase with functions") + self.assertEqual(len(summary.step_datas), 3) + self.assertEqual(summary.step_datas[0].name, "get with params") + self.assertEqual(summary.step_datas[1].name, "post raw text") + self.assertEqual(summary.step_datas[2].name, "post form data") diff --git a/httprunner/step_testcase.py b/httprunner/step_testcase.py index 0882428d..337ab21f 100644 --- a/httprunner/step_testcase.py +++ b/httprunner/step_testcase.py @@ -1,16 +1,11 @@ -import os -from typing import Text, Callable +from typing import Callable, Text from loguru import logger -from httprunner import exceptions -from httprunner.loader import load_testcase_file -from httprunner.step_request import call_hooks +from httprunner import exceptions +from httprunner.models import IStep, StepData, TStep from httprunner.runner import HttpRunner -from httprunner.models import ( - TStep, - StepData -) +from httprunner.step_request import call_hooks def run_step_testcase(runner: HttpRunner, step: TStep) -> StepData: @@ -25,9 +20,8 @@ def run_step_testcase(runner: HttpRunner, step: TStep) -> StepData: # TODO: override testcase with current step name/variables/export - ref_case_runner = HttpRunner() - ref_case_runner.config = step.testcase.config - ref_case_runner.teststeps = step.testcase.teststeps + # step.testcase is a referenced testcase, e.g. RequestWithFunctions + ref_case_runner = step.testcase() ref_case_runner.with_session(runner.session) \ .with_case_id(runner.case_id) \ .with_variables(step_variables) \ @@ -49,7 +43,7 @@ def run_step_testcase(runner: HttpRunner, step: TStep) -> StepData: return step_data -class StepRefCase(object): +class StepRefCase(IStep): def __init__(self, step: TStep): self.__step = step @@ -95,13 +89,9 @@ class RunTestCase(object): return self def call(self, testcase: Callable) -> StepRefCase: - if hasattr(testcase, "config") and hasattr(testcase, "teststeps"): + if issubclass(testcase, HttpRunner): + # referenced testcase object self.__step.testcase = testcase - elif isinstance(testcase, Text): - if not os.path.isfile(testcase): - raise exceptions.ParamsError(f"Invalid testcase path: {testcase}") - - self.__step.testcase = load_testcase_file(testcase) else: raise exceptions.ParamsError( f"Invalid teststep referenced testcase: {testcase}" diff --git a/httprunner/step_testcase_test.py b/httprunner/step_testcase_test.py new file mode 100644 index 00000000..926e8897 --- /dev/null +++ b/httprunner/step_testcase_test.py @@ -0,0 +1,23 @@ +import unittest + +from httprunner.runner import HttpRunner +from httprunner.step_testcase import RunTestCase +from examples.postman_echo.request_methods.request_with_functions_test import TestCaseRequestWithFunctions + + +class TestRunTestCase(unittest.TestCase): + + def setUp(self): + self.runner = HttpRunner() + + def test_run_testcase_by_path(self): + + step_data = RunTestCase("run referenced testcase").call( + TestCaseRequestWithFunctions + ).run(self.runner) + self.assertTrue(step_data.success) + self.assertEqual(step_data.name, "run referenced testcase") + self.assertEqual(len(step_data.data), 3) + self.assertEqual(step_data.data[0].name, "get with params") + self.assertEqual(step_data.data[1].name, "post raw text") + self.assertEqual(step_data.data[2].name, "post form data")