From 77fc3546e1622cc6fb1e944095d87ddb11164168 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Fri, 15 May 2020 11:34:21 +0800 Subject: [PATCH] change: update loader --- httprunner/new_loader.py | 49 ++++++ httprunner/parser.py | 6 +- httprunner/utils_test.py | 4 +- tests/test_runner.py | 364 --------------------------------------- 4 files changed, 54 insertions(+), 369 deletions(-) delete mode 100644 tests/test_runner.py diff --git a/httprunner/new_loader.py b/httprunner/new_loader.py index 192df285..f3b7130e 100644 --- a/httprunner/new_loader.py +++ b/httprunner/new_loader.py @@ -1,3 +1,4 @@ +import csv import importlib import io import json @@ -23,6 +24,7 @@ except AttributeError: project_meta_cached_mapping: Dict[str, ProjectMeta] = {} +project_working_directory: str = None def _load_yaml_file(yaml_file): @@ -120,6 +122,52 @@ def load_dot_env_file(dot_env_path): return env_variables_mapping +def load_csv_file(csv_file): + """ load csv file and check file content format + + Args: + csv_file (str): csv file path, csv file content is like below: + + Returns: + list: list of parameters, each parameter is in dict format + + Examples: + >>> cat csv_file + username,password + test1,111111 + test2,222222 + test3,333333 + + >>> load_csv_file(csv_file) + [ + {'username': 'test1', 'password': '111111'}, + {'username': 'test2', 'password': '222222'}, + {'username': 'test3', 'password': '333333'} + ] + + """ + if not os.path.isabs(csv_file): + global project_working_directory + if project_working_directory is None: + raise exceptions.MyBaseFailure("load_project_meta() has not been called!") + + # make compatible with Windows/Linux + csv_file = os.path.join(project_working_directory, *csv_file.split("/")) + + if not os.path.isfile(csv_file): + # file path not exist + raise exceptions.CSVNotFound(csv_file) + + csv_content_list = [] + + with io.open(csv_file, encoding="utf-8") as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + csv_content_list.append(row) + + return csv_content_list + + def load_folder_files(folder_path, recursive=True): """ load folder path, return all files endswith yml/yaml/json in list. @@ -284,6 +332,7 @@ def init_project_working_directory(test_path): # locate debugtalk.py file debugtalk_path = locate_debugtalk_py(test_path) + global project_working_directory if debugtalk_path: # The folder contains debugtalk.py will be treated as PWD. project_working_directory = os.path.dirname(debugtalk_path) diff --git a/httprunner/parser.py b/httprunner/parser.py index a43023e6..01aeec14 100644 --- a/httprunner/parser.py +++ b/httprunner/parser.py @@ -3,7 +3,7 @@ import builtins import re from typing import Any, Set, Text, Callable, List, Dict -from httprunner import loader, utils, exceptions +from httprunner import new_loader, utils, exceptions from httprunner.schema import VariablesMapping, FunctionsMapping absolute_http_url_regexp = re.compile(r"^https?://", re.I) @@ -222,7 +222,7 @@ def get_mapping_function( return functions_mapping[function_name] elif function_name in ["parameterize", "P"]: - return loader.load_csv_file + return new_loader.load_csv_file elif function_name in ["environ", "ENV"]: return utils.get_os_environ @@ -235,7 +235,7 @@ def get_mapping_function( try: # check if HttpRunner builtin functions - built_in_functions = loader.load_builtin_functions() + built_in_functions = new_loader.load_builtin_functions() return built_in_functions[function_name] except KeyError: pass diff --git a/httprunner/utils_test.py b/httprunner/utils_test.py index 9777aa05..2d1cbd17 100644 --- a/httprunner/utils_test.py +++ b/httprunner/utils_test.py @@ -2,7 +2,7 @@ import io import os import unittest -from httprunner import loader, utils +from httprunner import new_loader, utils class TestUtils(unittest.TestCase): @@ -16,7 +16,7 @@ class TestUtils(unittest.TestCase): def current_validators(self): from httprunner.builtin import comparators - functions_mapping = loader.load.load_module_functions(comparators) + functions_mapping = new_loader.load_module_functions(comparators) functions_mapping["equals"](None, None) functions_mapping["equals"](1, 1) diff --git a/tests/test_runner.py b/tests/test_runner.py deleted file mode 100644 index ab9f4805..00000000 --- a/tests/test_runner.py +++ /dev/null @@ -1,364 +0,0 @@ -import os -import time - -from httprunner import loader, parser, runner -from tests.api_server import HTTPBIN_SERVER -from tests.base import ApiServerUnittest - - -class TestRunner(ApiServerUnittest): - - def setUp(self): - project_mapping = loader.load_project_data(os.path.join(os.getcwd(), "tests")) - self.debugtalk_functions = project_mapping["functions"] - - config = { - "name": "XXX", - "base_url": "http://127.0.0.1", - "verify": False - } - self.test_runner = runner.Runner(config) - self.reset_all() - - def reset_all(self): - url = "%s/api/reset-all" % self.host - headers = self.get_authenticated_headers() - return self.api_client.get(url, headers=headers) - - def test_run_testcase_with_hooks(self): - start_time = time.time() - - testcases = [ - { - "config": { - "name": "basic test with httpbin", - "base_url": HTTPBIN_SERVER, - "setup_hooks": [ - "${sleep(0.5)}", - "${hook_print(setup)}" - ], - "teardown_hooks": [ - "${sleep(1)}", - "${hook_print(teardown)}" - ] - }, - "teststeps": [ - { - "name": "get token", - "request": { - "url": "http://127.0.0.1:5000/api/get-token", - "method": "POST", - "headers": { - "content-type": "application/json", - "user_agent": "iOS/10.3", - "device_sn": "HZfFBh6tU59EdXJ", - "os_platform": "ios", - "app_version": "2.8.6" - }, - "json": { - "sign": "5188962c489d1a35effa99e9346dd5efd4fdabad" - } - }, - "validate": [ - {"check": "status_code", "expect": 200} - ] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - end_time = time.time() - # check if testcase setup hook executed - self.assertGreater(end_time - start_time, 0.5) - - start_time = time.time() - test_runner.run_test(parsed_testcase["teststeps"][0]) - end_time = time.time() - # testcase teardown hook has not been executed now - self.assertLess(end_time - start_time, 2) - - def test_run_testcase_with_hooks_assignment(self): - testcases = [ - { - "config": { - "name": "basic test with httpbin", - "base_url": HTTPBIN_SERVER - }, - "teststeps": [ - { - "name": "modify request headers", - "base_url": HTTPBIN_SERVER, - "request": { - "url": "/anything", - "method": "POST", - "headers": { - "user_agent": "iOS/10.3", - "os_platform": "ios" - }, - "data": "a=1&b=2" - }, - "setup_hooks": [ - {"total": "${sum_two(1, 5)}"} - ], - "validate": [ - {"check": "status_code", "expect": 200} - ] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - test_runner.run_test(parsed_testcase["teststeps"][0]) - test_variables_mapping = test_runner.session_context.test_variables_mapping - self.assertEqual(test_variables_mapping["total"], 6) - self.assertEqual(test_variables_mapping["request"]["data"], "a=1&b=2") - - def test_run_testcase_with_hooks_modify_request(self): - testcases = [ - { - "config": { - "name": "basic test with httpbin", - "base_url": HTTPBIN_SERVER - }, - "teststeps": [ - { - "name": "modify request headers", - "base_url": HTTPBIN_SERVER, - "request": { - "url": "/anything", - "method": "POST", - "headers": { - "content-type": "application/json", - "user_agent": "iOS/10.3" - }, - "json": { - "os_platform": "ios", - "sign": "5188962c489d1a35effa99e9346dd5efd4fdabad" - } - }, - "setup_hooks": [ - "${modify_request_json($request, android)}" - ], - "validate": [ - {"check": "status_code", "expect": 200}, - {"check": "content.json.os_platform", "expect": "android"} - ] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - test_runner.run_test(parsed_testcase["teststeps"][0]) - - def test_run_testcase_with_teardown_hooks_success(self): - testcases = [ - { - "config": { - "name": "basic test with httpbin" - }, - "teststeps": [ - { - "name": "get token", - "request": { - "url": "http://127.0.0.1:5000/api/get-token", - "method": "POST", - "headers": { - "content-type": "application/json", - "user_agent": "iOS/10.3", - "device_sn": "HZfFBh6tU59EdXJ", - "os_platform": "ios", - "app_version": "2.8.6" - }, - "json": { - "sign": "5188962c489d1a35effa99e9346dd5efd4fdabad" - } - }, - "validate": [ - {"check": "status_code", "expect": 200} - ], - "teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - - start_time = time.time() - test_runner.run_test(parsed_testcase["teststeps"][0]) - end_time = time.time() - # check if teardown function executed - self.assertLess(end_time - start_time, 0.5) - - def test_run_testcase_with_teardown_hooks_fail(self): - testcases = [ - { - "config": { - "name": "basic test with httpbin" - }, - "teststeps": [ - { - "name": "get token", - "request": { - "url": "http://127.0.0.1:5000/api/get-token2", - "method": "POST", - "headers": { - "content-type": "application/json", - "user_agent": "iOS/10.3", - "device_sn": "HZfFBh6tU59EdXJ", - "os_platform": "ios", - "app_version": "2.8.6" - }, - "json": { - "sign": "5188962c489d1a35effa99e9346dd5efd4fdabad" - } - }, - "validate": [ - {"check": "status_code", "expect": 404} - ], - "teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - - start_time = time.time() - test_runner.run_test(parsed_testcase["teststeps"][0]) - end_time = time.time() - # check if teardown function executed - self.assertGreater(end_time - start_time, 2) - - def test_bugfix_type_match(self): - testcase_file_path = os.path.join( - os.getcwd(), 'tests/data/bugfix_type_match.yml') - tests_mapping = loader.load_cases(testcase_file_path) - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - test_runner.run_test(parsed_testcase["teststeps"][0]) - - def test_run_validate_elapsed(self): - testcases = [ - { - "config": {}, - "teststeps": [ - { - "name": "get token", - "request": { - "url": "http://127.0.0.1:5000/api/get-token", - "method": "POST", - "headers": { - "content-type": "application/json", - "user_agent": "iOS/10.3", - "device_sn": "HZfFBh6tU59EdXJ", - "os_platform": "ios", - "app_version": "2.8.6" - }, - "json": { - "sign": "5188962c489d1a35effa99e9346dd5efd4fdabad" - } - }, - "validate": [ - {"check": "status_code", "expect": 200}, - {"check": "elapsed.seconds", "comparator": "lt", "expect": 1}, - {"check": "elapsed.days", "comparator": "eq", "expect": 0}, - {"check": "elapsed.microseconds", "comparator": "gt", "expect": 1000}, - {"check": "elapsed.total_seconds", "comparator": "lt", "expect": 1} - ] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - test_runner.run_test(parsed_testcase["teststeps"][0]) - - def test_run_testcase_config_variables_parsed_from_function(self): - testcases = [ - { - "config": { - "name": "basic test with httpbin", - "base_url": HTTPBIN_SERVER, - "variables": "${gen_variables()}" - }, - "teststeps": [ - { - "name": "modify request headers", - "base_url": HTTPBIN_SERVER, - "request": { - "url": "/anything", - "method": "POST", - "headers": { - "user_agent": "iOS/10.3", - "os_platform": "ios" - }, - "data": "a=1&b=2" - }, - "validate": [ - {"check": "status_code", "expect": 200} - ] - } - ] - } - ] - tests_mapping = { - "project_mapping": { - "functions": self.debugtalk_functions - }, - "testcases": testcases - } - parsed_testcases = parser.parse_tests(tests_mapping) - parsed_testcase = parsed_testcases[0] - test_runner = runner.Runner(parsed_testcase["config"]) - test_runner.run_test(parsed_testcase["teststeps"][0]) - test_variables_mapping = test_runner.session_context.test_variables_mapping - self.assertEqual(test_variables_mapping["var_a"], 1) - self.assertEqual(test_variables_mapping["var_b"], 2) - self.assertEqual(test_variables_mapping["request"]["data"], "a=1&b=2")