Merge pull request #944 from httprunner/v3

## 3.1.1 (2020-06-23)

**Added**

- feat: add optional message for assertion

**Fixed**

- fix #942: type_match None
- fix: override referenced testcase export in teststep
- fix: avoid duplicate import
- fix: override locust weight
This commit is contained in:
debugtalk
2020-06-23 16:15:55 +08:00
committed by GitHub
15 changed files with 206 additions and 100 deletions
+13
View File
@@ -1,5 +1,18 @@
# Release History # Release History
## 3.1.1 (2020-06-23)
**Added**
- feat: add optional message for assertion
**Fixed**
- fix #942: type_match None
- fix: override referenced testcase export in teststep
- fix: avoid duplicate import
- fix: override locust weight
## 3.1.0 (2020-06-21) ## 3.1.0 (2020-06-21)
**Added** **Added**
Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 369 KiB

+2 -1
View File
@@ -175,10 +175,11 @@ Extract JSON response body with [jmespath][jmespath].
Extract JSON response body with [jmespath][jmespath] and validate with expected value. Extract JSON response body with [jmespath][jmespath] and validate with expected value.
> assert_XXX(jmes_path: Text, expected_value: Any) > assert_XXX(jmes_path: Text, expected_value: Any, message: Text = "")
- jmes_path: jmespath expression, refer to [JMESPath Tutorial][jmespath_tutorial] for more details - jmes_path: jmespath expression, refer to [JMESPath Tutorial][jmespath_tutorial] for more details
- expected_value: the specified expected value, variable or function reference can also be used here - expected_value: the specified expected value, variable or function reference can also be used here
- message (optional): used to indicate assertion error reason
The image below shows HttpRunner builtin validators. The image below shows HttpRunner builtin validators.
@@ -57,6 +57,9 @@ class TestCaseRequestWithFunctions(HttpRunner):
"body.data", "body.data",
"This is expected to be sent back as part of response body: bar12-$expect_foo2-bar21.", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar21.",
) )
.assert_type_match("body.json", "None")
.assert_type_match("body.json", "NoneType")
.assert_type_match("body.json", None)
), ),
Step( Step(
RunRequest("post form data") RunRequest("post form data")
@@ -70,7 +73,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
) )
.with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3") .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
.validate() .validate()
.assert_equal("status_code", 200) .assert_equal("status_code", 200, "response status code should be 200")
.assert_equal("body.form.foo1", "$expect_foo1") .assert_equal("body.form.foo1", "$expect_foo1")
.assert_equal("body.form.foo2", "bar23") .assert_equal("body.form.foo2", "bar23")
.assert_equal("body.form.foo3", "bar21") .assert_equal("body.form.foo3", "bar21")
@@ -48,6 +48,9 @@ teststeps:
validate: validate:
- eq: ["status_code", 200] - eq: ["status_code", 200]
- eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar21."] - eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar21."]
- type_match: ["body.json", None]
- type_match: ["body.json", NoneType]
- type_match: ["body.json", null]
- -
name: post form data name: post form data
variables: variables:
@@ -60,7 +63,7 @@ teststeps:
Content-Type: "application/x-www-form-urlencoded" Content-Type: "application/x-www-form-urlencoded"
data: "foo1=$foo1&foo2=$foo2&foo3=$foo3" data: "foo1=$foo1&foo2=$foo2&foo3=$foo3"
validate: validate:
- eq: ["status_code", 200] - eq: ["status_code", 200, "response status code should be 200"]
- eq: ["body.form.foo1", "$expect_foo1"] - eq: ["body.form.foo1", "$expect_foo1"]
- eq: ["body.form.foo2", "bar23"] - eq: ["body.form.foo2", "bar23"]
- eq: ["body.form.foo3", "bar21"] - eq: ["body.form.foo3", "bar21"]
@@ -57,6 +57,9 @@ class TestCaseRequestWithFunctions(HttpRunner):
"body.data", "body.data",
"This is expected to be sent back as part of response body: bar12-$expect_foo2-bar21.", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar21.",
) )
.assert_type_match("body.json", "None")
.assert_type_match("body.json", "NoneType")
.assert_type_match("body.json", None)
), ),
Step( Step(
RunRequest("post form data") RunRequest("post form data")
@@ -70,7 +73,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
) )
.with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3") .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
.validate() .validate()
.assert_equal("status_code", 200) .assert_equal("status_code", 200, "response status code should be 200")
.assert_equal("body.form.foo1", "$expect_foo1") .assert_equal("body.form.foo1", "$expect_foo1")
.assert_equal("body.form.foo2", "bar23") .assert_equal("body.form.foo2", "bar23")
.assert_equal("body.form.foo3", "bar21") .assert_equal("body.form.foo3", "bar21")
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = "3.1.0" __version__ = "3.1.1"
__description__ = "One-stop solution for HTTP(S) testing." __description__ = "One-stop solution for HTTP(S) testing."
# import firstly for monkey patch if needed # import firstly for monkey patch if needed
+77 -45
View File
@@ -3,72 +3,101 @@ Built-in validate comparators.
""" """
import re import re
from typing import Text, Any, Union
def equal(check_value, expect_value): def equal(check_value: Any, expect_value: Any, message: Text = ""):
assert check_value == expect_value assert check_value == expect_value, message
def greater_than(check_value, expect_value): def greater_than(
assert check_value > expect_value check_value: Union[int, float], expect_value: Union[int, float], message: Text = ""
):
assert check_value > expect_value, message
def less_than(check_value, expect_value): def less_than(
assert check_value < expect_value check_value: Union[int, float], expect_value: Union[int, float], message: Text = ""
):
assert check_value < expect_value, message
def greater_or_equals(check_value, expect_value): def greater_or_equals(
assert check_value >= expect_value check_value: Union[int, float], expect_value: Union[int, float], message: Text = ""
):
assert check_value >= expect_value, message
def less_or_equals(check_value, expect_value): def less_or_equals(
assert check_value <= expect_value check_value: Union[int, float], expect_value: Union[int, float], message: Text = ""
):
assert check_value <= expect_value, message
def not_equal(check_value, expect_value): def not_equal(check_value: Any, expect_value: Any, message: Text = ""):
assert check_value != expect_value assert check_value != expect_value, message
def string_equals(check_value, expect_value): def string_equals(check_value: Text, expect_value: Any, message: Text = ""):
assert str(check_value) == str(expect_value) assert str(check_value) == str(expect_value), message
def length_equal(check_value, expect_value): def length_equal(check_value: Text, expect_value: int, message: Text = ""):
assert isinstance(expect_value, int) assert isinstance(expect_value, int), "expect_value should be int type"
assert len(check_value) == expect_value assert len(check_value) == expect_value, message
def length_greater_than(check_value, expect_value): def length_greater_than(
assert isinstance(expect_value, (int, float)) check_value: Text, expect_value: Union[int, float], message: Text = ""
assert len(check_value) > expect_value ):
assert isinstance(
expect_value, (int, float)
), "expect_value should be int/float type"
assert len(check_value) > expect_value, message
def length_greater_or_equals(check_value, expect_value): def length_greater_or_equals(
assert isinstance(expect_value, (int, float)) check_value: Text, expect_value: Union[int, float], message: Text = ""
assert len(check_value) >= expect_value ):
assert isinstance(
expect_value, (int, float)
), "expect_value should be int/float type"
assert len(check_value) >= expect_value, message
def length_less_than(check_value, expect_value): def length_less_than(
assert isinstance(expect_value, (int, float)) check_value: Text, expect_value: Union[int, float], message: Text = ""
assert len(check_value) < expect_value ):
assert isinstance(
expect_value, (int, float)
), "expect_value should be int/float type"
assert len(check_value) < expect_value, message
def length_less_or_equals(check_value, expect_value): def length_less_or_equals(
assert isinstance(expect_value, (int, float)) check_value: Text, expect_value: Union[int, float], message: Text = ""
assert len(check_value) <= expect_value ):
assert isinstance(
expect_value, (int, float)
), "expect_value should be int/float type"
assert len(check_value) <= expect_value, message
def contains(check_value, expect_value): def contains(check_value: Any, expect_value: Any, message: Text = ""):
assert isinstance(check_value, (list, tuple, dict, str, bytes)) assert isinstance(
assert expect_value in check_value check_value, (list, tuple, dict, str, bytes)
), "expect_value should be list/tuple/dict/str/bytes type"
assert expect_value in check_value, message
def contained_by(check_value, expect_value): def contained_by(check_value: Any, expect_value: Any, message: Text = ""):
assert isinstance(expect_value, (list, tuple, dict, str, bytes)) assert isinstance(
assert check_value in expect_value check_value, (list, tuple, dict, str, bytes)
), "expect_value should be list/tuple/dict/str/bytes type"
assert check_value in expect_value, message
def type_match(check_value, expect_value): def type_match(check_value: Any, expect_value: Any, message: Text = ""):
def get_type(name): def get_type(name):
if isinstance(name, type): if isinstance(name, type):
return name return name
@@ -80,18 +109,21 @@ def type_match(check_value, expect_value):
else: else:
raise ValueError(name) raise ValueError(name)
assert isinstance(check_value, get_type(expect_value)) if expect_value in ["None", "NoneType", None]:
assert check_value is None, message
else:
assert type(check_value) == get_type(expect_value), message
def regex_match(check_value, expect_value): def regex_match(check_value: Text, expect_value: Any, message: Text = ""):
assert isinstance(expect_value, str) assert isinstance(expect_value, str), "expect_value should be Text type"
assert isinstance(check_value, str) assert isinstance(check_value, str), "check_value should be Text type"
assert re.match(expect_value, check_value) assert re.match(expect_value, check_value), message
def startswith(check_value, expect_value): def startswith(check_value: Any, expect_value: Any, message: Text = ""):
assert str(check_value).startswith(str(expect_value)) assert str(check_value).startswith(str(expect_value)), message
def endswith(check_value, expect_value): def endswith(check_value: Text, expect_value: Any, message: Text = ""):
assert str(check_value).endswith(str(expect_value)) assert str(check_value).endswith(str(expect_value)), message
+6 -1
View File
@@ -200,8 +200,13 @@ def ensure_testcase_v3_api(api_content: Dict) -> Dict:
teststep = _sort_step_by_custom_order(teststep) teststep = _sort_step_by_custom_order(teststep)
config = {"name": api_content["name"]}
extract_variable_names: List = list(teststep.get("extract", {}).keys())
if extract_variable_names:
config["export"] = extract_variable_names
return { return {
"config": {"name": api_content["name"]}, "config": config,
"teststeps": [teststep], "teststeps": [teststep],
} }
+17 -5
View File
@@ -310,6 +310,11 @@ def make_teststep_chain_style(teststep: Dict) -> Text:
expect = validator["expect"] expect = validator["expect"]
if isinstance(expect, Text): if isinstance(expect, Text):
expect = f'"{expect}"' expect = f'"{expect}"'
message = validator["message"]
if message:
step_info += f".assert_{assert_method}({check}, {expect}, '{message}')"
else:
step_info += f".assert_{assert_method}({check}, {expect})" step_info += f".assert_{assert_method}({check}, {expect})"
return f"Step({step_info})" return f"Step({step_info})"
@@ -362,6 +367,13 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text:
test_content.setdefault("config", {})["path"] = ref_testcase_path test_content.setdefault("config", {})["path"] = ref_testcase_path
ref_testcase_python_abs_path = make_testcase(test_content) ref_testcase_python_abs_path = make_testcase(test_content)
# override testcase export
ref_testcase_export: List = test_content["config"].get("export", [])
if ref_testcase_export:
step_export: List = teststep.setdefault("export", [])
step_export.extend(ref_testcase_export)
teststep["export"] = list(set(step_export))
# prepare ref testcase class name # prepare ref testcase class name
ref_testcase_cls_name = pytest_files_made_cache_mapping[ ref_testcase_cls_name = pytest_files_made_cache_mapping[
ref_testcase_python_abs_path ref_testcase_python_abs_path
@@ -374,9 +386,9 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text:
) )
ref_module_name, _ = os.path.splitext(ref_testcase_python_relative_path) ref_module_name, _ = os.path.splitext(ref_testcase_python_relative_path)
ref_module_name = ref_module_name.replace(os.sep, ".") ref_module_name = ref_module_name.replace(os.sep, ".")
imports_list.append( import_expr = f"from {ref_module_name} import TestCase{ref_testcase_cls_name} as {ref_testcase_cls_name}"
f"from {ref_module_name} import TestCase{ref_testcase_cls_name} as {ref_testcase_cls_name}" if import_expr not in imports_list:
) imports_list.append(import_expr)
testcase_path = convert_relative_project_root_dir(testcase_abs_path) testcase_path = convert_relative_project_root_dir(testcase_abs_path)
# current file compared to ProjectRootDir # current file compared to ProjectRootDir
@@ -462,8 +474,8 @@ def make_testsuite(testsuite: Dict) -> NoReturn:
testcase_dict["config"]["variables"].update(testcase_variables) testcase_dict["config"]["variables"].update(testcase_variables)
# override weight # override weight
weight = testcase.get("weight", 1) if "weight" in testcase:
testcase_dict["config"]["weight"] = weight testcase_dict["config"]["weight"] = testcase["weight"]
# make testcase # make testcase
testcase_pytest_path = make_testcase(testcase_dict, testsuite_dir) testcase_pytest_path = make_testcase(testcase_dict, testsuite_dir)
+27 -5
View File
@@ -80,6 +80,7 @@ def uniform_validator(validator):
# format1 # format1
check_item = validator["check"] check_item = validator["check"]
expect_value = validator["expect"] expect_value = validator["expect"]
message = validator.get("message", "")
comparator = validator.get("comparator", "eq") comparator = validator.get("comparator", "eq")
elif len(validator) == 1: elif len(validator) == 1:
@@ -87,10 +88,16 @@ def uniform_validator(validator):
comparator = list(validator.keys())[0] comparator = list(validator.keys())[0]
compare_values = validator[comparator] compare_values = validator[comparator]
if not isinstance(compare_values, list) or len(compare_values) != 2: if not isinstance(compare_values, list) or len(compare_values) not in [2, 3]:
raise ParamsError(f"invalid validator: {validator}") raise ParamsError(f"invalid validator: {validator}")
check_item, expect_value = compare_values check_item = compare_values[0]
expect_value = compare_values[1]
if len(compare_values) == 3:
message = compare_values[2]
else:
# len(compare_values) == 2
message = ""
else: else:
raise ParamsError(f"invalid validator: {validator}") raise ParamsError(f"invalid validator: {validator}")
@@ -98,7 +105,12 @@ def uniform_validator(validator):
# uniform comparator, e.g. lt => less_than, eq => equals # uniform comparator, e.g. lt => less_than, eq => equals
assert_method = get_uniform_comparator(comparator) assert_method = get_uniform_comparator(comparator)
return {"check": check_item, "expect": expect_value, "assert": assert_method} return {
"check": check_item,
"expect": expect_value,
"assert": assert_method,
"message": message,
}
class ResponseObject(object): class ResponseObject(object):
@@ -193,6 +205,11 @@ class ResponseObject(object):
# parse expected value with config/teststep/extracted variables # parse expected value with config/teststep/extracted variables
expect_value = parse_data(expect_item, variables_mapping, functions_mapping) expect_value = parse_data(expect_item, variables_mapping, functions_mapping)
# message
message = u_validator["message"]
# parse message with config/teststep/extracted variables
message = parse_data(message, variables_mapping, functions_mapping)
validate_msg = f"assert {check_item} {assert_method} {expect_value}({type(expect_value).__name__})" validate_msg = f"assert {check_item} {assert_method} {expect_value}({type(expect_value).__name__})"
validator_dict = { validator_dict = {
@@ -201,14 +218,15 @@ class ResponseObject(object):
"check_value": check_value, "check_value": check_value,
"expect": expect_item, "expect": expect_item,
"expect_value": expect_value, "expect_value": expect_value,
"message": message,
} }
try: try:
assert_func(check_value, expect_value) assert_func(check_value, expect_value, message)
validate_msg += "\t==> pass" validate_msg += "\t==> pass"
logger.info(validate_msg) logger.info(validate_msg)
validator_dict["check_result"] = "pass" validator_dict["check_result"] = "pass"
except AssertionError: except AssertionError as ex:
validate_pass = False validate_pass = False
validator_dict["check_result"] = "fail" validator_dict["check_result"] = "fail"
validate_msg += "\t==> fail" validate_msg += "\t==> fail"
@@ -219,6 +237,10 @@ class ResponseObject(object):
f"assert_method: {assert_method}\n" f"assert_method: {assert_method}\n"
f"expect_value: {expect_value}({type(expect_value).__name__})" f"expect_value: {expect_value}({type(expect_value).__name__})"
) )
message = str(ex)
if message:
validate_msg += f"\nmessage: {message}"
logger.error(validate_msg) logger.error(validate_msg)
failures.append(validate_msg) failures.append(validate_msg)
+42 -36
View File
@@ -71,140 +71,146 @@ class StepRequestValidation(object):
self.__step_context = step_context self.__step_context = step_context
def assert_equal( def assert_equal(
self, jmes_path: Text, expected_value: Any self, jmes_path: Text, expected_value: Any, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append({"equal": [jmes_path, expected_value]}) self.__step_context.validators.append(
{"equal": [jmes_path, expected_value, message]}
)
return self return self
def assert_not_equal( def assert_not_equal(
self, jmes_path: Text, expected_value: Any self, jmes_path: Text, expected_value: Any, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"not_equal": [jmes_path, expected_value]} {"not_equal": [jmes_path, expected_value, message]}
) )
return self return self
def assert_greater_than( def assert_greater_than(
self, jmes_path: Text, expected_value: Union[int, float] self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"greater_than": [jmes_path, expected_value]} {"greater_than": [jmes_path, expected_value, message]}
) )
return self return self
def assert_less_than( def assert_less_than(
self, jmes_path: Text, expected_value: Union[int, float] self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"less_than": [jmes_path, expected_value]} {"less_than": [jmes_path, expected_value, message]}
) )
return self return self
def assert_greater_or_equals( def assert_greater_or_equals(
self, jmes_path: Text, expected_value: Union[int, float] self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"greater_or_equals": [jmes_path, expected_value]} {"greater_or_equals": [jmes_path, expected_value, message]}
) )
return self return self
def assert_less_or_equals( def assert_less_or_equals(
self, jmes_path: Text, expected_value: Union[int, float] self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"less_or_equals": [jmes_path, expected_value]} {"less_or_equals": [jmes_path, expected_value, message]}
) )
return self return self
def assert_length_equal( def assert_length_equal(
self, jmes_path: Text, expected_value: int self, jmes_path: Text, expected_value: int, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"length_equal": [jmes_path, expected_value]} {"length_equal": [jmes_path, expected_value, message]}
) )
return self return self
def assert_length_greater_than( def assert_length_greater_than(
self, jmes_path: Text, expected_value: int self, jmes_path: Text, expected_value: int, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"length_greater_than": [jmes_path, expected_value]} {"length_greater_than": [jmes_path, expected_value, message]}
) )
return self return self
def assert_length_less_than( def assert_length_less_than(
self, jmes_path: Text, expected_value: int self, jmes_path: Text, expected_value: int, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"length_less_than": [jmes_path, expected_value]} {"length_less_than": [jmes_path, expected_value, message]}
) )
return self return self
def assert_length_greater_or_equals( def assert_length_greater_or_equals(
self, jmes_path: Text, expected_value: int self, jmes_path: Text, expected_value: int, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"length_greater_or_equals": [jmes_path, expected_value]} {"length_greater_or_equals": [jmes_path, expected_value, message]}
) )
return self return self
def assert_length_less_or_equals( def assert_length_less_or_equals(
self, jmes_path: Text, expected_value: int self, jmes_path: Text, expected_value: int, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"length_less_or_equals": [jmes_path, expected_value]} {"length_less_or_equals": [jmes_path, expected_value, message]}
) )
return self return self
def assert_string_equals( def assert_string_equals(
self, jmes_path: Text, expected_value: int self, jmes_path: Text, expected_value: int, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"string_equals": [jmes_path, expected_value]} {"string_equals": [jmes_path, expected_value, message]}
) )
return self return self
def assert_startswith( def assert_startswith(
self, jmes_path: Text, expected_value: Text self, jmes_path: Text, expected_value: Text, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"startswith": [jmes_path, expected_value]} {"startswith": [jmes_path, expected_value, message]}
) )
return self return self
def assert_endswith( def assert_endswith(
self, jmes_path: Text, expected_value: Text self, jmes_path: Text, expected_value: Text, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append({"endswith": [jmes_path, expected_value]}) self.__step_context.validators.append(
{"endswith": [jmes_path, expected_value, message]}
)
return self return self
def assert_regex_match( def assert_regex_match(
self, jmes_path: Text, expected_value: Text self, jmes_path: Text, expected_value: Text, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"regex_match": [jmes_path, expected_value]} {"regex_match": [jmes_path, expected_value, message]}
) )
return self return self
def assert_contains( def assert_contains(
self, jmes_path: Text, expected_value: Any self, jmes_path: Text, expected_value: Any, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append({"contains": [jmes_path, expected_value]}) self.__step_context.validators.append(
{"contains": [jmes_path, expected_value, message]}
)
return self return self
def assert_contained_by( def assert_contained_by(
self, jmes_path: Text, expected_value: Any self, jmes_path: Text, expected_value: Any, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"contained_by": [jmes_path, expected_value]} {"contained_by": [jmes_path, expected_value, message]}
) )
return self return self
def assert_type_match( def assert_type_match(
self, jmes_path: Text, expected_value: Text self, jmes_path: Text, expected_value: Any, message: Text = ""
) -> "StepRequestValidation": ) -> "StepRequestValidation":
self.__step_context.validators.append( self.__step_context.validators.append(
{"type_match": [jmes_path, expected_value]} {"type_match": [jmes_path, expected_value, message]}
) )
return self return self
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "httprunner" name = "httprunner"
version = "3.1.0" version = "3.1.1"
description = "One-stop solution for HTTP(S) testing." description = "One-stop solution for HTTP(S) testing."
license = "Apache-2.0" license = "Apache-2.0"
readme = "README.md" readme = "README.md"
+4 -1
View File
@@ -95,7 +95,10 @@ class TestCompat(unittest.TestCase):
self.assertEqual( self.assertEqual(
compat.ensure_testcase_v3_api(api_content), compat.ensure_testcase_v3_api(api_content),
{ {
"config": {"name": "get with params"}, "config": {
"name": "get with params",
"export": ["varA", "user_agent"],
},
"teststeps": [ "teststeps": [
{ {
"name": "get with params", "name": "get with params",
+3
View File
@@ -69,6 +69,9 @@ class TestUtils(unittest.TestCase):
functions_mapping["type_match"]([1], "list") functions_mapping["type_match"]([1], "list")
functions_mapping["type_match"]({}, "dict") functions_mapping["type_match"]({}, "dict")
functions_mapping["type_match"]({"a": 1}, "dict") functions_mapping["type_match"]({"a": 1}, "dict")
functions_mapping["type_match"](None, "None")
functions_mapping["type_match"](None, "NoneType")
functions_mapping["type_match"](None, None)
def test_lower_dict_keys(self): def test_lower_dict_keys(self):
request_dict = { request_dict = {