diff --git a/httprunner/loader.py b/httprunner/loader.py index 0ea7e2db..b0e6d7b9 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -1,3 +1,4 @@ +import collections import csv import io import json @@ -5,6 +6,7 @@ import os import yaml from httprunner import exceptions, logger, parser, utils, validator +from httprunner.compat import OrderedDict ############################################################################### ## file loader @@ -289,7 +291,7 @@ def _load_test_file(file_path): if "api" in test_block: ref_call = test_block["api"] def_block = _get_block_by_name(ref_call, "api") - utils._override_block(def_block, test_block) + _override_block(def_block, test_block) testset["testcases"].append(test_block) elif "suite" in test_block: ref_call = test_block["suite"] @@ -355,6 +357,147 @@ def _get_test_definition(name, ref_type): return block +def _override_block(def_block, current_block): + """ override def_block with current_block + @param def_block: + { + "name": "get token", + "request": {...}, + "validate": [{'eq': ['status_code', 200]}] + } + @param current_block: + { + "name": "get token", + "extract": [{"token": "content.token"}], + "validate": [{'eq': ['status_code', 201]}, {'len_eq': ['content.token', 16]}] + } + @return + { + "name": "get token", + "request": {...}, + "extract": [{"token": "content.token"}], + "validate": [{'eq': ['status_code', 201]}, {'len_eq': ['content.token', 16]}] + } + """ + def_validators = def_block.get("validate") or def_block.get("validators", []) + current_validators = current_block.get("validate") or current_block.get("validators", []) + + def_extrators = def_block.get("extract") \ + or def_block.get("extractors") \ + or def_block.get("extract_binds", []) + current_extractors = current_block.get("extract") \ + or current_block.get("extractors") \ + or current_block.get("extract_binds", []) + + current_block.update(def_block) + current_block["validate"] = _merge_validator( + def_validators, + current_validators + ) + current_block["extract"] = _merge_extractor( + def_extrators, + current_extractors + ) + + +def _get_validators_mapping(validators): + """ get validators mapping from api or test validators + @param (list) validators: + [ + {"check": "v1", "expect": 201, "comparator": "eq"}, + {"check": {"b": 1}, "expect": 200, "comparator": "eq"} + ] + @return + { + ("v1", "eq"): {"check": "v1", "expect": 201, "comparator": "eq"}, + ('{"b": 1}', "eq"): {"check": {"b": 1}, "expect": 200, "comparator": "eq"} + } + """ + validators_mapping = {} + + for validator in validators: + validator = parser.parse_validator(validator) + + if not isinstance(validator["check"], collections.Hashable): + check = json.dumps(validator["check"]) + else: + check = validator["check"] + + key = (check, validator["comparator"]) + validators_mapping[key] = validator + + return validators_mapping + + +def _merge_validator(def_validators, current_validators): + """ merge def_validators with current_validators + @params: + def_validators: [{'eq': ['v1', 200]}, {"check": "s2", "expect": 16, "comparator": "len_eq"}] + current_validators: [{"check": "v1", "expect": 201}, {'len_eq': ['s3', 12]}] + @return: + [ + {"check": "v1", "expect": 201, "comparator": "eq"}, + {"check": "s2", "expect": 16, "comparator": "len_eq"}, + {"check": "s3", "expect": 12, "comparator": "len_eq"} + ] + """ + if not def_validators: + return current_validators + + elif not current_validators: + return def_validators + + else: + api_validators_mapping = _get_validators_mapping(def_validators) + test_validators_mapping = _get_validators_mapping(current_validators) + + api_validators_mapping.update(test_validators_mapping) + return list(api_validators_mapping.values()) + + +def _merge_extractor(def_extrators, current_extractors): + """ merge def_extrators with current_extractors + @params: + def_extrators: [{"var1": "val1"}, {"var2": "val2"}] + current_extractors: [{"var1": "val111"}, {"var3": "val3"}] + @return: + [ + {"var1": "val111"}, + {"var2": "val2"}, + {"var3": "val3"} + ] + """ + if not def_extrators: + return current_extractors + + elif not current_extractors: + return def_extrators + + else: + extractor_dict = OrderedDict() + for api_extrator in def_extrators: + if len(api_extrator) != 1: + logger.log_warning("incorrect extractor: {}".format(api_extrator)) + continue + + var_name = list(api_extrator.keys())[0] + extractor_dict[var_name] = api_extrator[var_name] + + for test_extrator in current_extractors: + if len(test_extrator) != 1: + logger.log_warning("incorrect extractor: {}".format(test_extrator)) + continue + + var_name = list(test_extrator.keys())[0] + extractor_dict[var_name] = test_extrator[var_name] + + extractor_list = [] + for key, value in extractor_dict.items(): + extractor_list.append({key: value}) + + return extractor_list + + def load_testcases(path): """ load testcases from file path @param path: path could be in several type diff --git a/httprunner/parser.py b/httprunner/parser.py index 283ecf9a..906f30e1 100644 --- a/httprunner/parser.py +++ b/httprunner/parser.py @@ -5,7 +5,7 @@ import os import random import re -from httprunner import exceptions, loader, logger, utils +from httprunner import exceptions, loader, utils from httprunner.compat import (OrderedDict, basestring, builtin_str, numeric_types, str) diff --git a/httprunner/utils.py b/httprunner/utils.py index 217933a2..21141524 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -1,6 +1,5 @@ # encoding: utf-8 -import collections import copy import hashlib import hmac @@ -15,7 +14,7 @@ import string import types from datetime import datetime -from httprunner import exceptions, logger, parser +from httprunner import exceptions, logger from httprunner.compat import (OrderedDict, basestring, builtin_str, is_py2, is_py3, numeric_types, str) from requests.structures import CaseInsensitiveDict @@ -145,147 +144,6 @@ def substitute_variables_with_mapping(content, mapping): return content -def _get_validators_mapping(validators): - """ get validators mapping from api or test validators - @param (list) validators: - [ - {"check": "v1", "expect": 201, "comparator": "eq"}, - {"check": {"b": 1}, "expect": 200, "comparator": "eq"} - ] - @return - { - ("v1", "eq"): {"check": "v1", "expect": 201, "comparator": "eq"}, - ('{"b": 1}', "eq"): {"check": {"b": 1}, "expect": 200, "comparator": "eq"} - } - """ - validators_mapping = {} - - for validator in validators: - validator = parser.parse_validator(validator) - - if not isinstance(validator["check"], collections.Hashable): - check = json.dumps(validator["check"]) - else: - check = validator["check"] - - key = (check, validator["comparator"]) - validators_mapping[key] = validator - - return validators_mapping - - -def _merge_validator(def_validators, current_validators): - """ merge def_validators with current_validators - @params: - def_validators: [{'eq': ['v1', 200]}, {"check": "s2", "expect": 16, "comparator": "len_eq"}] - current_validators: [{"check": "v1", "expect": 201}, {'len_eq': ['s3', 12]}] - @return: - [ - {"check": "v1", "expect": 201, "comparator": "eq"}, - {"check": "s2", "expect": 16, "comparator": "len_eq"}, - {"check": "s3", "expect": 12, "comparator": "len_eq"} - ] - """ - if not def_validators: - return current_validators - - elif not current_validators: - return def_validators - - else: - api_validators_mapping = _get_validators_mapping(def_validators) - test_validators_mapping = _get_validators_mapping(current_validators) - - api_validators_mapping.update(test_validators_mapping) - return list(api_validators_mapping.values()) - - -def _merge_extractor(def_extrators, current_extractors): - """ merge def_extrators with current_extractors - @params: - def_extrators: [{"var1": "val1"}, {"var2": "val2"}] - current_extractors: [{"var1": "val111"}, {"var3": "val3"}] - @return: - [ - {"var1": "val111"}, - {"var2": "val2"}, - {"var3": "val3"} - ] - """ - if not def_extrators: - return current_extractors - - elif not current_extractors: - return def_extrators - - else: - extractor_dict = OrderedDict() - for api_extrator in def_extrators: - if len(api_extrator) != 1: - logger.log_warning("incorrect extractor: {}".format(api_extrator)) - continue - - var_name = list(api_extrator.keys())[0] - extractor_dict[var_name] = api_extrator[var_name] - - for test_extrator in current_extractors: - if len(test_extrator) != 1: - logger.log_warning("incorrect extractor: {}".format(test_extrator)) - continue - - var_name = list(test_extrator.keys())[0] - extractor_dict[var_name] = test_extrator[var_name] - - extractor_list = [] - for key, value in extractor_dict.items(): - extractor_list.append({key: value}) - - return extractor_list - - -def _override_block(def_block, current_block): - """ override def_block with current_block - @param def_block: - { - "name": "get token", - "request": {...}, - "validate": [{'eq': ['status_code', 200]}] - } - @param current_block: - { - "name": "get token", - "extract": [{"token": "content.token"}], - "validate": [{'eq': ['status_code', 201]}, {'len_eq': ['content.token', 16]}] - } - @return - { - "name": "get token", - "request": {...}, - "extract": [{"token": "content.token"}], - "validate": [{'eq': ['status_code', 201]}, {'len_eq': ['content.token', 16]}] - } - """ - def_validators = def_block.get("validate") or def_block.get("validators", []) - current_validators = current_block.get("validate") or current_block.get("validators", []) - - def_extrators = def_block.get("extract") \ - or def_block.get("extractors") \ - or def_block.get("extract_binds", []) - current_extractors = current_block.get("extract") \ - or current_block.get("extractors") \ - or current_block.get("extract_binds", []) - - current_block.update(def_block) - current_block["validate"] = _merge_validator( - def_validators, - current_validators - ) - current_block["extract"] = _merge_extractor( - def_extrators, - current_extractors - ) - - def get_uniform_comparator(comparator): """ convert comparator alias to uniform name """ diff --git a/tests/test_loader.py b/tests/test_loader.py index 5013bd9c..fa059ab1 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -1,7 +1,7 @@ import os import unittest -from httprunner import exceptions, loader, utils +from httprunner import exceptions, loader class TestFileLoader(unittest.TestCase): @@ -211,7 +211,7 @@ class TestSuiteLoader(unittest.TestCase): ] } - utils._override_block(def_block, test_block) + loader._override_block(def_block, test_block) self.assertEqual(test_block["name"], "override block") self.assertIn({'check': 'status_code', 'expect': 201, 'comparator': 'eq'}, test_block["validate"]) self.assertIn({'check': 'content.token', 'comparator': 'len_eq', 'expect': 32}, test_block["validate"]) @@ -234,6 +234,63 @@ class TestSuiteLoader(unittest.TestCase): with self.assertRaises(exceptions.SuiteNotFound): loader._get_test_definition("create_and_check_XXX", "suite") + def test_merge_validator(self): + def_validators = [ + {'eq': ['v1', 200]}, + {"check": "s2", "expect": 16, "comparator": "len_eq"} + ] + current_validators = [ + {"check": "v1", "expect": 201}, + {'len_eq': ['s3', 12]} + ] + + merged_validators = loader._merge_validator(def_validators, current_validators) + self.assertIn( + {"check": "v1", "expect": 201, "comparator": "eq"}, + merged_validators + ) + self.assertIn( + {"check": "s2", "expect": 16, "comparator": "len_eq"}, + merged_validators + ) + self.assertIn( + {"check": "s3", "expect": 12, "comparator": "len_eq"}, + merged_validators + ) + + def test_merge_validator_with_dict(self): + def_validators = [ + {'eq': ["a", {"v": 1}]}, + {'eq': [{"b": 1}, 200]} + ] + current_validators = [ + {'len_eq': ['s3', 12]}, + {'eq': [{"b": 1}, 201]} + ] + + merged_validators = loader._merge_validator(def_validators, current_validators) + self.assertEqual(len(merged_validators), 3) + self.assertIn({'check': {'b': 1}, 'expect': 201, 'comparator': 'eq'}, merged_validators) + self.assertNotIn({'check': {'b': 1}, 'expect': 200, 'comparator': 'eq'}, merged_validators) + + def test_merge_extractor(self): + api_extrators = [{"var1": "val1"}, {"var2": "val2"}] + current_extractors = [{"var1": "val111"}, {"var3": "val3"}] + + merged_extractors = loader._merge_extractor(api_extrators, current_extractors) + self.assertIn( + {"var1": "val111"}, + merged_extractors + ) + self.assertIn( + {"var2": "val2"}, + merged_extractors + ) + self.assertIn( + {"var3": "val3"}, + merged_extractors + ) + def test_load_testcases_by_path_files(self): testsets_list = [] diff --git a/tests/test_utils.py b/tests/test_utils.py index df114c5e..e59e078f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -88,63 +88,6 @@ class TestUtils(ApiServerUnittest): self.assertFalse(result["request"]["data"]["false"]) self.assertEqual("", result["request"]["data"]["empty_str"]) - def test_merge_validator(self): - def_validators = [ - {'eq': ['v1', 200]}, - {"check": "s2", "expect": 16, "comparator": "len_eq"} - ] - current_validators = [ - {"check": "v1", "expect": 201}, - {'len_eq': ['s3', 12]} - ] - - merged_validators = utils._merge_validator(def_validators, current_validators) - self.assertIn( - {"check": "v1", "expect": 201, "comparator": "eq"}, - merged_validators - ) - self.assertIn( - {"check": "s2", "expect": 16, "comparator": "len_eq"}, - merged_validators - ) - self.assertIn( - {"check": "s3", "expect": 12, "comparator": "len_eq"}, - merged_validators - ) - - def test_merge_validator_with_dict(self): - def_validators = [ - {'eq': ["a", {"v": 1}]}, - {'eq': [{"b": 1}, 200]} - ] - current_validators = [ - {'len_eq': ['s3', 12]}, - {'eq': [{"b": 1}, 201]} - ] - - merged_validators = utils._merge_validator(def_validators, current_validators) - self.assertEqual(len(merged_validators), 3) - self.assertIn({'check': {'b': 1}, 'expect': 201, 'comparator': 'eq'}, merged_validators) - self.assertNotIn({'check': {'b': 1}, 'expect': 200, 'comparator': 'eq'}, merged_validators) - - def test_merge_extractor(self): - api_extrators = [{"var1": "val1"}, {"var2": "val2"}] - current_extractors = [{"var1": "val111"}, {"var3": "val3"}] - - merged_extractors = utils._merge_extractor(api_extrators, current_extractors) - self.assertIn( - {"var1": "val111"}, - merged_extractors - ) - self.assertIn( - {"var2": "val2"}, - merged_extractors - ) - self.assertIn( - {"var3": "val3"}, - merged_extractors - ) - def test_get_uniform_comparator(self): self.assertEqual(utils.get_uniform_comparator("eq"), "equals") self.assertEqual(utils.get_uniform_comparator("=="), "equals")