mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-04 23:16:57 +08:00
fix: run referenced testcase in python
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# NOTE: Generated By HttpRunner v3.1.7
|
# NOTE: Generated By HttpRunner v4.0.0-alpha
|
||||||
# FROM: basic.yml
|
# FROM: basic.yml
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# NOTE: Generated By HttpRunner v3.1.7
|
# NOTE: Generated By HttpRunner v4.0.0-alpha
|
||||||
# FROM: hooks.yml
|
# FROM: hooks.yml
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# NOTE: Generated By HttpRunner v3.1.7
|
# NOTE: Generated By HttpRunner v4.0.0-alpha
|
||||||
# FROM: load_image.yml
|
# FROM: load_image.yml
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# NOTE: Generated By HttpRunner v3.1.7
|
# NOTE: Generated By HttpRunner v4.0.0-alpha
|
||||||
# FROM: upload.yml
|
# FROM: upload.yml
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# NOTE: Generated By HttpRunner v3.1.7
|
# NOTE: Generated By HttpRunner v4.0.0-alpha
|
||||||
# FROM: validate.yml
|
# FROM: validate.yml
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(help="sub-command help")
|
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)
|
sub_parser_make = init_make_parser(subparsers)
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
|
|||||||
+12
-2
@@ -5,7 +5,8 @@ import unittest
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from httprunner.cli import main
|
from httprunner import loader
|
||||||
|
from httprunner.cli import main, main_run
|
||||||
|
|
||||||
|
|
||||||
class TestCli(unittest.TestCase):
|
class TestCli(unittest.TestCase):
|
||||||
@@ -45,8 +46,17 @@ class TestCli(unittest.TestCase):
|
|||||||
try:
|
try:
|
||||||
os.chdir(os.path.join(cwd, "examples", "postman_echo"))
|
os.chdir(os.path.join(cwd, "examples", "postman_echo"))
|
||||||
exit_code = pytest.main(
|
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)
|
self.assertEqual(exit_code, 0)
|
||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
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"))
|
||||||
|
|||||||
+7
-10
@@ -1,11 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any
|
from typing import Any, Callable, Dict, List, Text, Union
|
||||||
from typing import Dict, Text, Union, Callable
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field, HttpUrl
|
||||||
from pydantic import HttpUrl
|
|
||||||
|
|
||||||
Name = Text
|
Name = Text
|
||||||
Url = Text
|
Url = Text
|
||||||
@@ -156,14 +153,14 @@ class SessionData(BaseModel):
|
|||||||
class StepData(BaseModel):
|
class StepData(BaseModel):
|
||||||
"""teststep data, each step maybe corresponding to one request or one testcase"""
|
"""teststep data, each step maybe corresponding to one request or one testcase"""
|
||||||
|
|
||||||
name: Text = "" # teststep name
|
name: Text = "" # teststep name
|
||||||
step_type: Text = "" # teststep type, request or testcase
|
step_type: Text = "" # teststep type, request or testcase
|
||||||
success: bool = False
|
success: bool = False
|
||||||
data: Union[SessionData, List['StepData']] = None
|
data: Union[SessionData, List['StepData']] = None
|
||||||
elapsed: float = 0.0 # teststep elapsed time
|
elapsed: float = 0.0 # teststep elapsed time
|
||||||
content_size: float = 0 # response content size
|
content_size: float = 0 # response content size
|
||||||
export_vars: VariablesMapping = {}
|
export_vars: VariablesMapping = {}
|
||||||
attachment: Text = "" # teststep attachment
|
attachment: Text = "" # teststep attachment
|
||||||
|
|
||||||
|
|
||||||
StepData.update_forward_refs()
|
StepData.update_forward_refs()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import unittest
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from httprunner.parser import Parser
|
||||||
from httprunner.response import ResponseObject
|
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):
|
def test_extract(self):
|
||||||
variables_mapping = {
|
variables_mapping = {
|
||||||
'body': 'body'
|
'body': 'body'
|
||||||
}
|
}
|
||||||
functions_mapping = {
|
|
||||||
'get_name': lambda: 'name',
|
|
||||||
}
|
|
||||||
extract_mapping = self.resp_obj.extract(
|
extract_mapping = self.resp_obj.extract(
|
||||||
{
|
{
|
||||||
"var_1": "body.json.locations[0]",
|
"var_1": "body.json.locations[0]",
|
||||||
@@ -35,7 +37,6 @@ class TestResponse(unittest.TestCase):
|
|||||||
"var_4": "$body.json.locations[3].${get_name()}",
|
"var_4": "$body.json.locations[3].${get_name()}",
|
||||||
},
|
},
|
||||||
variables_mapping=variables_mapping,
|
variables_mapping=variables_mapping,
|
||||||
functions_mapping=functions_mapping,
|
|
||||||
)
|
)
|
||||||
self.assertEqual(extract_mapping["var_1"], {"name": "Seattle", "state": "WA"})
|
self.assertEqual(extract_mapping["var_1"], {"name": "Seattle", "state": "WA"})
|
||||||
self.assertEqual(extract_mapping["var_2"], "Olympia")
|
self.assertEqual(extract_mapping["var_2"], "Olympia")
|
||||||
@@ -62,9 +63,7 @@ class TestResponse(unittest.TestCase):
|
|||||||
|
|
||||||
def test_validate_functions(self):
|
def test_validate_functions(self):
|
||||||
variables_mapping = {"index": 1}
|
variables_mapping = {"index": 1}
|
||||||
functions_mapping = {"get_num": lambda x: x}
|
|
||||||
self.resp_obj.validate(
|
self.resp_obj.validate(
|
||||||
[{"eq": ["${get_num(0)}", 0]}, {"eq": ["${get_num($index)}", 1]},],
|
[{"eq": ["${get_num(0)}", 0]}, {"eq": ["${get_num($index)}", 1]},],
|
||||||
variables_mapping=variables_mapping,
|
variables_mapping=variables_mapping,
|
||||||
functions_mapping=functions_mapping,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ from loguru import logger
|
|||||||
from httprunner.client import HttpSession
|
from httprunner.client import HttpSession
|
||||||
from httprunner.config import Config
|
from httprunner.config import Config
|
||||||
from httprunner.exceptions import ParamsError
|
from httprunner.exceptions import ParamsError
|
||||||
from httprunner.loader import load_project_meta
|
from httprunner.loader import load_project_meta, load_testcase_file
|
||||||
from httprunner.models import (ProjectMeta, StepData, TConfig, TestCaseInOut,
|
from httprunner.models import (ProjectMeta, StepData, TConfig, TestCase,
|
||||||
TestCaseSummary, TestCaseTime, VariablesMapping)
|
TestCaseInOut, TestCaseSummary, TestCaseTime,
|
||||||
|
VariablesMapping)
|
||||||
from httprunner.parser import Parser
|
from httprunner.parser import Parser
|
||||||
from httprunner.utils import merge_variables
|
from httprunner.utils import merge_variables
|
||||||
|
|
||||||
@@ -175,11 +176,9 @@ class HttpRunner(object):
|
|||||||
|
|
||||||
logger.info(f"run step end: {step.name()} <<<<<<\n")
|
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"""
|
"""main entrance, discovered by pytest"""
|
||||||
self.__init()
|
self.__init()
|
||||||
log_handler = logger.add(self.__log_path, level="DEBUG")
|
|
||||||
|
|
||||||
self.__parse_config(param)
|
self.__parse_config(param)
|
||||||
|
|
||||||
if USE_ALLURE:
|
if USE_ALLURE:
|
||||||
@@ -191,6 +190,7 @@ class HttpRunner(object):
|
|||||||
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}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log_handler = logger.add(self.__log_path, level="DEBUG")
|
||||||
self.__start_at = time.time()
|
self.__start_at = time.time()
|
||||||
try:
|
try:
|
||||||
# run step in sequential order
|
# run step in sequential order
|
||||||
|
|||||||
@@ -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"))
|
|
||||||
@@ -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")
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
import os
|
from typing import Callable, Text
|
||||||
from typing import Text, Callable
|
|
||||||
|
|
||||||
from loguru import logger
|
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.runner import HttpRunner
|
||||||
from httprunner.models import (
|
from httprunner.step_request import call_hooks
|
||||||
TStep,
|
|
||||||
StepData
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run_step_testcase(runner: HttpRunner, step: TStep) -> StepData:
|
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
|
# TODO: override testcase with current step name/variables/export
|
||||||
|
|
||||||
ref_case_runner = HttpRunner()
|
# step.testcase is a referenced testcase, e.g. RequestWithFunctions
|
||||||
ref_case_runner.config = step.testcase.config
|
ref_case_runner = step.testcase()
|
||||||
ref_case_runner.teststeps = step.testcase.teststeps
|
|
||||||
ref_case_runner.with_session(runner.session) \
|
ref_case_runner.with_session(runner.session) \
|
||||||
.with_case_id(runner.case_id) \
|
.with_case_id(runner.case_id) \
|
||||||
.with_variables(step_variables) \
|
.with_variables(step_variables) \
|
||||||
@@ -49,7 +43,7 @@ def run_step_testcase(runner: HttpRunner, step: TStep) -> StepData:
|
|||||||
return step_data
|
return step_data
|
||||||
|
|
||||||
|
|
||||||
class StepRefCase(object):
|
class StepRefCase(IStep):
|
||||||
def __init__(self, step: TStep):
|
def __init__(self, step: TStep):
|
||||||
self.__step = step
|
self.__step = step
|
||||||
|
|
||||||
@@ -95,13 +89,9 @@ class RunTestCase(object):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def call(self, testcase: Callable) -> StepRefCase:
|
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
|
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:
|
else:
|
||||||
raise exceptions.ParamsError(
|
raise exceptions.ParamsError(
|
||||||
f"Invalid teststep referenced testcase: {testcase}"
|
f"Invalid teststep referenced testcase: {testcase}"
|
||||||
|
|||||||
@@ -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")
|
||||||
Reference in New Issue
Block a user