change: update loader

This commit is contained in:
debugtalk
2020-05-15 11:34:21 +08:00
parent 46d3793244
commit 647d8c6312
4 changed files with 54 additions and 369 deletions

View File

@@ -1,3 +1,4 @@
import csv
import importlib import importlib
import io import io
import json import json
@@ -23,6 +24,7 @@ except AttributeError:
project_meta_cached_mapping: Dict[str, ProjectMeta] = {} project_meta_cached_mapping: Dict[str, ProjectMeta] = {}
project_working_directory: str = None
def _load_yaml_file(yaml_file): def _load_yaml_file(yaml_file):
@@ -120,6 +122,52 @@ def load_dot_env_file(dot_env_path):
return env_variables_mapping 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): def load_folder_files(folder_path, recursive=True):
""" load folder path, return all files endswith yml/yaml/json in list. """ 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 # locate debugtalk.py file
debugtalk_path = locate_debugtalk_py(test_path) debugtalk_path = locate_debugtalk_py(test_path)
global project_working_directory
if debugtalk_path: if debugtalk_path:
# The folder contains debugtalk.py will be treated as PWD. # The folder contains debugtalk.py will be treated as PWD.
project_working_directory = os.path.dirname(debugtalk_path) project_working_directory = os.path.dirname(debugtalk_path)

View File

@@ -3,7 +3,7 @@ import builtins
import re import re
from typing import Any, Set, Text, Callable, List, Dict 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 from httprunner.schema import VariablesMapping, FunctionsMapping
absolute_http_url_regexp = re.compile(r"^https?://", re.I) absolute_http_url_regexp = re.compile(r"^https?://", re.I)
@@ -222,7 +222,7 @@ def get_mapping_function(
return functions_mapping[function_name] return functions_mapping[function_name]
elif function_name in ["parameterize", "P"]: elif function_name in ["parameterize", "P"]:
return loader.load_csv_file return new_loader.load_csv_file
elif function_name in ["environ", "ENV"]: elif function_name in ["environ", "ENV"]:
return utils.get_os_environ return utils.get_os_environ
@@ -235,7 +235,7 @@ def get_mapping_function(
try: try:
# check if HttpRunner builtin functions # 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] return built_in_functions[function_name]
except KeyError: except KeyError:
pass pass

View File

@@ -2,7 +2,7 @@ import io
import os import os
import unittest import unittest
from httprunner import loader, utils from httprunner import new_loader, utils
class TestUtils(unittest.TestCase): class TestUtils(unittest.TestCase):
@@ -16,7 +16,7 @@ class TestUtils(unittest.TestCase):
def current_validators(self): def current_validators(self):
from httprunner.builtin import comparators 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"](None, None)
functions_mapping["equals"](1, 1) functions_mapping["equals"](1, 1)

View File

@@ -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")