mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-09 22:44:05 +08:00
#29: refactor validator:
1, relocate validate functions; 2, add unittest for custom defined validators.
This commit is contained in:
@@ -4,7 +4,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from httprunner import utils
|
from httprunner import exception, utils
|
||||||
from httprunner.testcase import TestcaseParser
|
from httprunner.testcase import TestcaseParser
|
||||||
|
|
||||||
|
|
||||||
@@ -165,10 +165,47 @@ class Context(object):
|
|||||||
def get_testcase_variables_mapping(self):
|
def get_testcase_variables_mapping(self):
|
||||||
return self.testcase_variables_mapping
|
return self.testcase_variables_mapping
|
||||||
|
|
||||||
def get_testcase_functions_mapping(self):
|
|
||||||
return self.testcase_functions_config
|
|
||||||
|
|
||||||
def exec_content_functions(self, content):
|
def exec_content_functions(self, content):
|
||||||
""" execute functions in content.
|
""" execute functions in content.
|
||||||
"""
|
"""
|
||||||
self.testcase_parser.eval_content_functions(content)
|
self.testcase_parser.eval_content_functions(content)
|
||||||
|
|
||||||
|
def do_validation(self, validator_dict):
|
||||||
|
""" validate with functions
|
||||||
|
"""
|
||||||
|
comparator = utils.get_uniform_comparator(validator_dict["comparator"])
|
||||||
|
validate_func = self.testcase_parser.get_bind_item("function", comparator)
|
||||||
|
|
||||||
|
if not validate_func:
|
||||||
|
raise exception.FunctionNotFound("comparator not found: {}".format(comparator))
|
||||||
|
|
||||||
|
check_item = validator_dict["check_item"]
|
||||||
|
check_value = validator_dict["check_value"]
|
||||||
|
expect_value = validator_dict["expect_value"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
if check_value is None or expect_value is None:
|
||||||
|
assert comparator in ["is", "eq", "equals", "=="]
|
||||||
|
|
||||||
|
validate_func(validator_dict["check_value"], validator_dict["expect_value"])
|
||||||
|
except (AssertionError, TypeError):
|
||||||
|
err_msg = "\n" + "\n".join([
|
||||||
|
"\tcheck item name: %s;" % check_item,
|
||||||
|
"\tcheck item value: %s (%s);" % (check_value, type(check_value).__name__),
|
||||||
|
"\tcomparator: %s;" % comparator,
|
||||||
|
"\texpected value: %s (%s)." % (expect_value, type(expect_value).__name__)
|
||||||
|
])
|
||||||
|
raise exception.ValidationError(err_msg)
|
||||||
|
|
||||||
|
def validate(self, validators, resp_obj):
|
||||||
|
""" check validators with the context variable mapping.
|
||||||
|
@param (list) validators
|
||||||
|
@param (object) resp_obj
|
||||||
|
"""
|
||||||
|
variables_mapping = self.get_testcase_variables_mapping()
|
||||||
|
|
||||||
|
for validator in validators:
|
||||||
|
validator_dict = resp_obj.parse_validator(validator, variables_mapping)
|
||||||
|
self.do_validation(validator_dict)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|||||||
@@ -189,39 +189,3 @@ class ResponseObject(object):
|
|||||||
"comparator": comparator
|
"comparator": comparator
|
||||||
}
|
}
|
||||||
return validator_dict
|
return validator_dict
|
||||||
|
|
||||||
def do_validation(self, validator_dict, functions_mapping):
|
|
||||||
""" validate with functions
|
|
||||||
"""
|
|
||||||
comparator = utils.get_uniform_comparator(validator_dict["comparator"])
|
|
||||||
|
|
||||||
validate_func = functions_mapping.get(comparator)
|
|
||||||
if not validate_func:
|
|
||||||
raise exception.FunctionNotFound("comparator not found: {}".format(comparator))
|
|
||||||
|
|
||||||
check_item = validator_dict["check_item"]
|
|
||||||
check_value = validator_dict["check_value"]
|
|
||||||
expect_value = validator_dict["expect_value"]
|
|
||||||
|
|
||||||
try:
|
|
||||||
if check_value is None or expect_value is None:
|
|
||||||
assert comparator in ["is", "eq", "equals", "=="]
|
|
||||||
|
|
||||||
validate_func(validator_dict["check_value"], validator_dict["expect_value"])
|
|
||||||
except (AssertionError, TypeError):
|
|
||||||
err_msg = "\n" + "\n".join([
|
|
||||||
"\tcheck item name: %s;" % check_item,
|
|
||||||
"\tcheck item value: %s (%s);" % (check_value, type(check_value).__name__),
|
|
||||||
"\tcomparator: %s;" % comparator,
|
|
||||||
"\texpected value: %s (%s)." % (expect_value, type(expect_value).__name__)
|
|
||||||
])
|
|
||||||
raise exception.ValidationError(err_msg)
|
|
||||||
|
|
||||||
def validate(self, validators, variables_mapping, functions_mapping):
|
|
||||||
""" check validators with the context variable mapping.
|
|
||||||
"""
|
|
||||||
for validator in validators:
|
|
||||||
validator_dict = self.parse_validator(validator, variables_mapping)
|
|
||||||
self.do_validation(validator_dict, functions_mapping)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|||||||
@@ -129,11 +129,7 @@ class Runner(object):
|
|||||||
self.context.bind_extracted_variables(extracted_variables_mapping)
|
self.context.bind_extracted_variables(extracted_variables_mapping)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp_obj.validate(
|
self.context.validate(validators, resp_obj)
|
||||||
validators,
|
|
||||||
self.context.get_testcase_variables_mapping(),
|
|
||||||
self.context.get_testcase_functions_mapping()
|
|
||||||
)
|
|
||||||
except (exception.ParamsError, exception.ResponseError, exception.ValidationError):
|
except (exception.ParamsError, exception.ResponseError, exception.ValidationError):
|
||||||
err_msg = u"Exception occured.\n"
|
err_msg = u"Exception occured.\n"
|
||||||
err_msg += u"HTTP request url: {}\n".format(url)
|
err_msg += u"HTTP request url: {}\n".format(url)
|
||||||
|
|||||||
@@ -30,3 +30,13 @@ get_sign_lambda = lambda *args: hmac.new(
|
|||||||
|
|
||||||
def gen_md5(*args):
|
def gen_md5(*args):
|
||||||
return hashlib.md5("".join(args).encode('utf-8')).hexdigest()
|
return hashlib.md5("".join(args).encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
|
def sum_status_code(status_code, expect_sum):
|
||||||
|
""" sum status code digits
|
||||||
|
e.g. 400 => 4, 201 => 3
|
||||||
|
"""
|
||||||
|
sum_value = 0
|
||||||
|
for digit in str(status_code):
|
||||||
|
sum_value += int(digit)
|
||||||
|
|
||||||
|
assert sum_value == expect_sum
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
{"eq": ["status_code", 200]},
|
{"eq": ["status_code", 200]},
|
||||||
{"len_eq": ["content.token", 16]},
|
{"len_eq": ["content.token", 16]},
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 200},
|
{"check": "status_code", "comparator": "eq", "expect": 200},
|
||||||
|
{"sum_status_code": ["status_code", 2]},
|
||||||
{"check": "content.token", "comparator": "len_eq", "expect": 16}
|
{"check": "content.token", "comparator": "len_eq", "expect": 16}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -49,6 +50,7 @@
|
|||||||
{"eq": ["status_code", 201]},
|
{"eq": ["status_code", 201]},
|
||||||
{"eq": ["content.success", true]},
|
{"eq": ["content.success", true]},
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 201},
|
{"check": "status_code", "comparator": "eq", "expect": 201},
|
||||||
|
{"sum_status_code": ["status_code", 3]},
|
||||||
{"check": "content.success", "comparator": "eq", "expect": true}
|
{"check": "content.success", "comparator": "eq", "expect": true}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -73,6 +75,7 @@
|
|||||||
{"eq": ["status_code", 500]},
|
{"eq": ["status_code", 500]},
|
||||||
{"eq": ["content.success", false]},
|
{"eq": ["content.success", false]},
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 500},
|
{"check": "status_code", "comparator": "eq", "expect": 500},
|
||||||
|
{"sum_status_code": ["status_code", 5]},
|
||||||
{"check": "content.success", "comparator": "eq", "expect": false}
|
{"check": "content.success", "comparator": "eq", "expect": false}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
- token: content.token
|
- token: content.token
|
||||||
validate:
|
validate:
|
||||||
- eq: ["status_code", 200]
|
- eq: ["status_code", 200]
|
||||||
|
- len_eq: ["token", 16]
|
||||||
- len_eq: ["content.token", 16]
|
- len_eq: ["content.token", 16]
|
||||||
- {"check": "status_code", "comparator": "eq", "expect": 200}
|
- {"check": "status_code", "comparator": "eq", "expect": 200}
|
||||||
- {"check": "content.token", "comparator": "len_eq", "expect": 16}
|
- sum_status_code: ["status_code", 2]
|
||||||
|
- {"check": "token", "comparator": "len_eq", "expect": 16}
|
||||||
|
|
||||||
- test:
|
- test:
|
||||||
name: create user which does not exist
|
name: create user which does not exist
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
password: "123456"
|
password: "123456"
|
||||||
validate:
|
validate:
|
||||||
- eq: ["status_code", 201]
|
- eq: ["status_code", 201]
|
||||||
|
- sum_status_code: ["status_code", 3]
|
||||||
- eq: ["content.success", True]
|
- eq: ["content.success", True]
|
||||||
- {"check": "status_code", "comparator": "eq", "expect": 201}
|
- {"check": "status_code", "comparator": "eq", "expect": 201}
|
||||||
- {"check": "content.success", "comparator": "eq", "expect": true}
|
- {"check": "content.success", "comparator": "eq", "expect": true}
|
||||||
@@ -51,6 +54,7 @@
|
|||||||
password: "123456"
|
password: "123456"
|
||||||
validate:
|
validate:
|
||||||
- "eq": ["status_code", 500]
|
- "eq": ["status_code", 500]
|
||||||
|
- sum_status_code: ["status_code", 5]
|
||||||
- "eq": ["content.success", false]
|
- "eq": ["content.success", false]
|
||||||
- {"check": "status_code", "comparator": "eq", "expect": 500}
|
- {"check": "status_code", "comparator": "eq", "expect": 500}
|
||||||
- {"check": "content.success", "comparator": "eq", "expect": false}
|
- {"check": "content.success", "comparator": "eq", "expect": false}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import unittest
|
|
||||||
|
|
||||||
from httprunner import runner, testcase, utils
|
import requests
|
||||||
|
from httprunner import exception, response, runner, testcase, utils
|
||||||
from httprunner.context import Context
|
from httprunner.context import Context
|
||||||
from httprunner.exception import ParamsError
|
from tests.base import ApiServerUnittest
|
||||||
|
|
||||||
|
|
||||||
class VariableBindsUnittest(unittest.TestCase):
|
class VariableBindsUnittest(ApiServerUnittest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.context = Context()
|
self.context = Context()
|
||||||
@@ -217,3 +217,72 @@ class VariableBindsUnittest(unittest.TestCase):
|
|||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
elapsed_time = end_time - start_time
|
elapsed_time = end_time - start_time
|
||||||
self.assertGreater(elapsed_time, 1)
|
self.assertGreater(elapsed_time, 1)
|
||||||
|
|
||||||
|
def test_do_validation(self):
|
||||||
|
self.context.do_validation(
|
||||||
|
{"check_item": "check_item", "check_value": 1, "expect_value": 1, "comparator": "eq"}
|
||||||
|
)
|
||||||
|
self.context.do_validation(
|
||||||
|
{"check_item": "check_item", "check_value": "abc", "expect_value": "abc", "comparator": "=="}
|
||||||
|
)
|
||||||
|
|
||||||
|
config_dict = {
|
||||||
|
"path": 'tests/data/demo_testset_hardcode.yml'
|
||||||
|
}
|
||||||
|
self.context.config_context(config_dict, "testset")
|
||||||
|
self.context.do_validation(
|
||||||
|
{"check_item": "status_code", "check_value": "201", "expect_value": 3, "comparator": "sum_status_code"}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_validate(self):
|
||||||
|
url = "http://127.0.0.1:5000/"
|
||||||
|
resp = requests.get(url)
|
||||||
|
resp_obj = response.ResponseObject(resp)
|
||||||
|
|
||||||
|
validators = [
|
||||||
|
{"eq": ["resp_status_code", 201]},
|
||||||
|
{"check": "resp_status_code", "comparator": "eq", "expect": 201},
|
||||||
|
{"check": "resp_body_success", "comparator": "eq", "expect": True}
|
||||||
|
]
|
||||||
|
variables = [
|
||||||
|
{"resp_status_code": 200},
|
||||||
|
{"resp_body_success": True}
|
||||||
|
]
|
||||||
|
self.context.bind_variables(variables)
|
||||||
|
|
||||||
|
with self.assertRaises(exception.ValidationError):
|
||||||
|
self.context.validate(validators, resp_obj)
|
||||||
|
|
||||||
|
variables = [
|
||||||
|
{"resp_status_code": 201},
|
||||||
|
{"resp_body_success": True}
|
||||||
|
]
|
||||||
|
self.context.bind_variables(variables)
|
||||||
|
|
||||||
|
self.assertTrue(self.context.validate(validators, resp_obj))
|
||||||
|
|
||||||
|
def test_validate_exception(self):
|
||||||
|
url = "http://127.0.0.1:5000/"
|
||||||
|
resp = requests.get(url)
|
||||||
|
resp_obj = response.ResponseObject(resp)
|
||||||
|
|
||||||
|
# expected value missed in validators
|
||||||
|
validators = [
|
||||||
|
{"eq": ["resp_status_code", 201]},
|
||||||
|
{"check": "resp_status_code", "comparator": "eq", "expect": 201},
|
||||||
|
{"check": "resp_body_success", "comparator": "eq", "expect": True}
|
||||||
|
]
|
||||||
|
variables = []
|
||||||
|
self.context.bind_variables(variables)
|
||||||
|
|
||||||
|
with self.assertRaises(exception.ParamsError):
|
||||||
|
self.context.validate(validators, resp_obj)
|
||||||
|
|
||||||
|
# expected value missed in variables mapping
|
||||||
|
variables = [
|
||||||
|
{"resp_status_code": 200}
|
||||||
|
]
|
||||||
|
self.context.bind_variables(variables)
|
||||||
|
|
||||||
|
with self.assertRaises(exception.ValidationError):
|
||||||
|
self.context.validate(validators, resp_obj)
|
||||||
|
|||||||
@@ -230,70 +230,3 @@ class TestResponse(ApiServerUnittest):
|
|||||||
resp_obj = response.ResponseObject(resp)
|
resp_obj = response.ResponseObject(resp)
|
||||||
with self.assertRaises(exception.ParamsError):
|
with self.assertRaises(exception.ParamsError):
|
||||||
resp_obj.extract_response(extract_binds_list)
|
resp_obj.extract_response(extract_binds_list)
|
||||||
|
|
||||||
def test_do_validation(self):
|
|
||||||
url = "http://127.0.0.1:5000/"
|
|
||||||
resp = requests.get(url)
|
|
||||||
resp_obj = response.ResponseObject(resp)
|
|
||||||
|
|
||||||
resp_obj.do_validation(
|
|
||||||
{"check_item": "check_item", "check_value": 1, "expect_value": 1, "comparator": "eq"},
|
|
||||||
self.functions_mapping
|
|
||||||
)
|
|
||||||
resp_obj.do_validation(
|
|
||||||
{"check_item": "check_item", "check_value": "abc", "expect_value": "abc", "comparator": "=="},
|
|
||||||
self.functions_mapping
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_validate(self):
|
|
||||||
url = "http://127.0.0.1:5000/"
|
|
||||||
resp = requests.get(url)
|
|
||||||
resp_obj = response.ResponseObject(resp)
|
|
||||||
|
|
||||||
validators = [
|
|
||||||
{"check": "resp_status_code", "comparator": "eq", "expect": 201},
|
|
||||||
{"check": "resp_body_success", "comparator": "eq", "expect": True}
|
|
||||||
]
|
|
||||||
variables_mapping = {
|
|
||||||
"resp_status_code": 200,
|
|
||||||
"resp_body_success": True
|
|
||||||
}
|
|
||||||
|
|
||||||
with self.assertRaises(exception.ValidationError):
|
|
||||||
resp_obj.validate(validators, variables_mapping, self.functions_mapping)
|
|
||||||
|
|
||||||
validators = [
|
|
||||||
{"check": "resp_status_code", "comparator": "eq", "expect": 201},
|
|
||||||
{"check": "resp_body_success", "comparator": "eq", "expect": True}
|
|
||||||
]
|
|
||||||
variables_mapping = {
|
|
||||||
"resp_status_code": 201,
|
|
||||||
"resp_body_success": True
|
|
||||||
}
|
|
||||||
|
|
||||||
self.assertTrue(resp_obj.validate(validators, variables_mapping, self.functions_mapping))
|
|
||||||
|
|
||||||
def test_validate_exception(self):
|
|
||||||
url = "http://127.0.0.1:5000/"
|
|
||||||
resp = requests.get(url)
|
|
||||||
resp_obj = response.ResponseObject(resp)
|
|
||||||
|
|
||||||
# expected value missed in validators
|
|
||||||
validators = [
|
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 201},
|
|
||||||
{"check": "body_success", "comparator": "eq"}
|
|
||||||
]
|
|
||||||
variables_mapping = {}
|
|
||||||
with self.assertRaises(exception.ValidationError):
|
|
||||||
resp_obj.validate(validators, variables_mapping, self.functions_mapping)
|
|
||||||
|
|
||||||
# expected value missed in variables mapping
|
|
||||||
validators = [
|
|
||||||
{"check": "resp_status_code", "comparator": "eq", "expect": 201},
|
|
||||||
{"check": "body_success", "comparator": "eq"}
|
|
||||||
]
|
|
||||||
variables_mapping = {
|
|
||||||
"resp_status_code": 200
|
|
||||||
}
|
|
||||||
with self.assertRaises(exception.ValidationError):
|
|
||||||
resp_obj.validate(validators, variables_mapping, self.functions_mapping)
|
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ class TestRunner(ApiServerUnittest):
|
|||||||
def test_run_single_testcase(self):
|
def test_run_single_testcase(self):
|
||||||
for testcase_file_path in self.testcase_file_path_list:
|
for testcase_file_path in self.testcase_file_path_list:
|
||||||
testcases = testcase._load_file(testcase_file_path)
|
testcases = testcase._load_file(testcase_file_path)
|
||||||
|
|
||||||
|
config_dict = {
|
||||||
|
"path": testcase_file_path
|
||||||
|
}
|
||||||
|
self.test_runner.init_config(config_dict, "testset")
|
||||||
|
|
||||||
test = testcases[0]["test"]
|
test = testcases[0]["test"]
|
||||||
self.assertTrue(self.test_runner._run_test(test))
|
self.assertTrue(self.test_runner._run_test(test))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user