mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-12 16:01:27 +08:00
Merge pull request #625 from HttpRunner/optimize_JSON_testcase_format
Optimize json testcase format
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,5 +1,15 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
|
## 2.2.0 (2019-06-24)
|
||||||
|
|
||||||
|
**Features**
|
||||||
|
|
||||||
|
- support testcase/testsuite in format version 2
|
||||||
|
|
||||||
|
**Bugfixes**
|
||||||
|
|
||||||
|
- add wheel in dev packages
|
||||||
|
|
||||||
## 2.1.3 (2019-04-24)
|
## 2.1.3 (2019-04-24)
|
||||||
|
|
||||||
**Bugfixes**
|
**Bugfixes**
|
||||||
|
|||||||
1
Pipfile
1
Pipfile
@@ -20,5 +20,6 @@ coveralls = "*"
|
|||||||
twine = "*"
|
twine = "*"
|
||||||
contextlib2 = "*"
|
contextlib2 = "*"
|
||||||
locustio = "*"
|
locustio = "*"
|
||||||
|
wheel = "*"
|
||||||
|
|
||||||
[scripts]
|
[scripts]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
__title__ = 'HttpRunner'
|
__title__ = 'HttpRunner'
|
||||||
__description__ = 'One-stop solution for HTTP(S) testing.'
|
__description__ = 'One-stop solution for HTTP(S) testing.'
|
||||||
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
||||||
__version__ = '2.1.3'
|
__version__ = '2.2.0'
|
||||||
__author__ = 'debugtalk'
|
__author__ = 'debugtalk'
|
||||||
__author_email__ = 'mail@debugtalk.com'
|
__author_email__ = 'mail@debugtalk.com'
|
||||||
__license__ = 'Apache-2.0'
|
__license__ = 'Apache-2.0'
|
||||||
|
|||||||
@@ -442,15 +442,55 @@ def load_testcase(raw_testcase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def load_testcase_v2(raw_testcase):
|
||||||
|
""" load testcase in format version 2.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
raw_testcase (dict): raw testcase content loaded from JSON/YAML file:
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "xxx",
|
||||||
|
"variables": {}
|
||||||
|
}
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "teststep 1",
|
||||||
|
"request" {...}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "teststep 2",
|
||||||
|
"request" {...}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: loaded testcase content
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"teststeps": [test11, test12]
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
raw_teststeps = raw_testcase.pop("teststeps")
|
||||||
|
raw_testcase["teststeps"] = [
|
||||||
|
load_teststep(teststep)
|
||||||
|
for teststep in raw_teststeps
|
||||||
|
]
|
||||||
|
return raw_testcase
|
||||||
|
|
||||||
|
|
||||||
def load_testsuite(raw_testsuite):
|
def load_testsuite(raw_testsuite):
|
||||||
""" load testsuite with testcase references.
|
""" load testsuite with testcase references.
|
||||||
|
support two different formats.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
raw_testsuite (dict): raw testsuite content loaded from JSON/YAML file:
|
raw_testsuite (dict): raw testsuite content loaded from JSON/YAML file:
|
||||||
|
# version 1, compatible with version < 2.2.0
|
||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"name": "",
|
"name": "xxx",
|
||||||
"request": {}
|
"variables": {}
|
||||||
}
|
}
|
||||||
"testcases": {
|
"testcases": {
|
||||||
"testcase1": {
|
"testcase1": {
|
||||||
@@ -462,6 +502,23 @@ def load_testsuite(raw_testsuite):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# version 2, implemented in 2.2.0
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "xxx",
|
||||||
|
"variables": {}
|
||||||
|
}
|
||||||
|
"testcases": [
|
||||||
|
{
|
||||||
|
"name": "testcase1",
|
||||||
|
"testcase": "/path/to/testcase",
|
||||||
|
"variables": {...},
|
||||||
|
"parameters": {...}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: loaded testsuite content
|
dict: loaded testsuite content
|
||||||
{
|
{
|
||||||
@@ -470,10 +527,26 @@ def load_testsuite(raw_testsuite):
|
|||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
testcases = raw_testsuite["testcases"]
|
raw_testcases = raw_testsuite.pop("testcases")
|
||||||
for name, raw_testcase in testcases.items():
|
raw_testsuite["testcases"] = {}
|
||||||
__extend_with_testcase_ref(raw_testcase)
|
|
||||||
raw_testcase.setdefault("name", name)
|
if isinstance(raw_testcases, dict):
|
||||||
|
# make compatible with version < 2.2.0
|
||||||
|
for name, raw_testcase in raw_testcases.items():
|
||||||
|
__extend_with_testcase_ref(raw_testcase)
|
||||||
|
raw_testcase.setdefault("name", name)
|
||||||
|
raw_testsuite["testcases"][name] = raw_testcase
|
||||||
|
|
||||||
|
elif isinstance(raw_testcases, list):
|
||||||
|
# format version 2, implemented in 2.2.0
|
||||||
|
for raw_testcase in raw_testcases:
|
||||||
|
__extend_with_testcase_ref(raw_testcase)
|
||||||
|
testcase_name = raw_testcase["name"]
|
||||||
|
raw_testsuite["testcases"][testcase_name] = raw_testcase
|
||||||
|
|
||||||
|
else:
|
||||||
|
# invalid format
|
||||||
|
raise exceptions.FileFormatError("Invalid testsuite format!")
|
||||||
|
|
||||||
return raw_testsuite
|
return raw_testsuite
|
||||||
|
|
||||||
@@ -523,18 +596,27 @@ def load_test_file(path):
|
|||||||
loaded_content = load_testsuite(raw_content)
|
loaded_content = load_testsuite(raw_content)
|
||||||
loaded_content["path"] = path
|
loaded_content["path"] = path
|
||||||
loaded_content["type"] = "testsuite"
|
loaded_content["type"] = "testsuite"
|
||||||
|
|
||||||
|
elif "teststeps" in raw_content:
|
||||||
|
# file_type: testcase (format version 2)
|
||||||
|
loaded_content = load_testcase_v2(raw_content)
|
||||||
|
loaded_content["path"] = path
|
||||||
|
loaded_content["type"] = "testcase"
|
||||||
|
|
||||||
elif "request" in raw_content:
|
elif "request" in raw_content:
|
||||||
# file_type: api
|
# file_type: api
|
||||||
# TODO: add json schema validation for api
|
# TODO: add json schema validation for api
|
||||||
loaded_content = raw_content
|
loaded_content = raw_content
|
||||||
loaded_content["path"] = path
|
loaded_content["path"] = path
|
||||||
loaded_content["type"] = "api"
|
loaded_content["type"] = "api"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# invalid format
|
# invalid format
|
||||||
logger.log_warning("Invalid test file format: {}".format(path))
|
raise exceptions.FileFormatError("Invalid test file format!")
|
||||||
|
|
||||||
elif isinstance(raw_content, list) and len(raw_content) > 0:
|
elif isinstance(raw_content, list) and len(raw_content) > 0:
|
||||||
# file_type: testcase
|
# file_type: testcase
|
||||||
|
# make compatible with version < 2.2.0
|
||||||
# TODO: add json schema validation for testcase
|
# TODO: add json schema validation for testcase
|
||||||
loaded_content = load_testcase(raw_content)
|
loaded_content = load_testcase(raw_content)
|
||||||
loaded_content["path"] = path
|
loaded_content["path"] = path
|
||||||
@@ -542,7 +624,7 @@ def load_test_file(path):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
# invalid format
|
# invalid format
|
||||||
logger.log_warning("Invalid test file format: {}".format(path))
|
raise exceptions.FileFormatError("Invalid test file format!")
|
||||||
|
|
||||||
return loaded_content
|
return loaded_content
|
||||||
|
|
||||||
@@ -776,7 +858,11 @@ def load_tests(path, dot_env_path=None):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __load_file_content(path):
|
def __load_file_content(path):
|
||||||
loaded_content = load_test_file(path)
|
try:
|
||||||
|
loaded_content = load_test_file(path)
|
||||||
|
except exceptions.FileFormatError:
|
||||||
|
logger.log_warning("Invalid test file format: {}".format(path))
|
||||||
|
|
||||||
if not loaded_content:
|
if not loaded_content:
|
||||||
pass
|
pass
|
||||||
elif loaded_content["type"] == "testsuite":
|
elif loaded_content["type"] == "testsuite":
|
||||||
|
|||||||
@@ -292,26 +292,60 @@ class TestSuiteLoader(unittest.TestCase):
|
|||||||
self.assertEqual(loaded_content["request"]["url"], "/api/users/$uid")
|
self.assertEqual(loaded_content["request"]["url"], "/api/users/$uid")
|
||||||
|
|
||||||
def test_load_test_file_testcase(self):
|
def test_load_test_file_testcase(self):
|
||||||
loaded_content = loader.load_test_file("tests/testcases/setup.yml")
|
for loaded_content in [
|
||||||
self.assertEqual(loaded_content["type"], "testcase")
|
loader.load_test_file("tests/testcases/setup.yml"),
|
||||||
self.assertIn("path", loaded_content)
|
loader.load_test_file("tests/testcases/setup.json")
|
||||||
self.assertIn("config", loaded_content)
|
]:
|
||||||
self.assertEqual(loaded_content["config"]["name"], "setup and reset all.")
|
self.assertEqual(loaded_content["type"], "testcase")
|
||||||
self.assertIn("teststeps", loaded_content)
|
self.assertIn("path", loaded_content)
|
||||||
self.assertEqual(len(loaded_content["teststeps"]), 2)
|
self.assertIn("config", loaded_content)
|
||||||
|
self.assertEqual(loaded_content["config"]["name"], "setup and reset all.")
|
||||||
|
self.assertIn("teststeps", loaded_content)
|
||||||
|
self.assertEqual(len(loaded_content["teststeps"]), 2)
|
||||||
|
|
||||||
|
def test_load_test_file_testcase_v2(self):
|
||||||
|
for loaded_content in [
|
||||||
|
loader.load_test_file("tests/testcases/setup.v2.yml"),
|
||||||
|
loader.load_test_file("tests/testcases/setup.v2.json")
|
||||||
|
]:
|
||||||
|
self.assertEqual(loaded_content["type"], "testcase")
|
||||||
|
self.assertIn("path", loaded_content)
|
||||||
|
self.assertIn("config", loaded_content)
|
||||||
|
self.assertEqual(loaded_content["config"]["name"], "setup and reset all.")
|
||||||
|
self.assertIn("teststeps", loaded_content)
|
||||||
|
self.assertEqual(len(loaded_content["teststeps"]), 2)
|
||||||
|
|
||||||
def test_load_test_file_testsuite(self):
|
def test_load_test_file_testsuite(self):
|
||||||
loaded_content = loader.load_test_file("tests/testsuites/create_users.yml")
|
for loaded_content in [
|
||||||
self.assertEqual(loaded_content["type"], "testsuite")
|
loader.load_test_file("tests/testsuites/create_users.yml"),
|
||||||
|
loader.load_test_file("tests/testsuites/create_users.json")
|
||||||
|
]:
|
||||||
|
self.assertEqual(loaded_content["type"], "testsuite")
|
||||||
|
|
||||||
testcases = loaded_content["testcases"]
|
testcases = loaded_content["testcases"]
|
||||||
self.assertEqual(len(testcases), 2)
|
self.assertEqual(len(testcases), 2)
|
||||||
self.assertIn('create user 1000 and check result.', testcases)
|
self.assertIn('create user 1000 and check result.', testcases)
|
||||||
self.assertIn('testcase_def', testcases["create user 1000 and check result."])
|
self.assertIn('testcase_def', testcases["create user 1000 and check result."])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcases["create user 1000 and check result."]["testcase_def"]["config"]["name"],
|
testcases["create user 1000 and check result."]["testcase_def"]["config"]["name"],
|
||||||
"create user and check result."
|
"create user and check result."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_load_test_file_testsuite_v2(self):
|
||||||
|
for loaded_content in [
|
||||||
|
loader.load_test_file("tests/testsuites/create_users.v2.yml"),
|
||||||
|
loader.load_test_file("tests/testsuites/create_users.v2.json")
|
||||||
|
]:
|
||||||
|
self.assertEqual(loaded_content["type"], "testsuite")
|
||||||
|
|
||||||
|
testcases = loaded_content["testcases"]
|
||||||
|
self.assertEqual(len(testcases), 2)
|
||||||
|
self.assertIn('create user 1000 and check result.', testcases)
|
||||||
|
self.assertIn('testcase_def', testcases["create user 1000 and check result."])
|
||||||
|
self.assertEqual(
|
||||||
|
testcases["create user 1000 and check result."]["testcase_def"]["config"]["name"],
|
||||||
|
"create user and check result."
|
||||||
|
)
|
||||||
|
|
||||||
def test_load_tests_api_file(self):
|
def test_load_tests_api_file(self):
|
||||||
path = os.path.join(
|
path = os.path.join(
|
||||||
|
|||||||
59
tests/testcases/setup.json
Normal file
59
tests/testcases/setup.json
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "setup and reset all.",
|
||||||
|
"output": [
|
||||||
|
"session_token"
|
||||||
|
],
|
||||||
|
"verify": false,
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "TESTCASE_SETUP_XXX",
|
||||||
|
"app_version": "2.8.6",
|
||||||
|
"os_platform": "ios",
|
||||||
|
"user_agent": "iOS/10.3"
|
||||||
|
},
|
||||||
|
"base_url": "http://127.0.0.1:5000",
|
||||||
|
"id": "setup_and_reset"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"eq": [
|
||||||
|
"status_code",
|
||||||
|
200
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"len_eq": [
|
||||||
|
"content.token",
|
||||||
|
16
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api": "api/get_token.yml",
|
||||||
|
"extract": [
|
||||||
|
{
|
||||||
|
"session_token": "content.token"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "$device_sn",
|
||||||
|
"app_version": "2.8.6",
|
||||||
|
"os_platform": "ios",
|
||||||
|
"user_agent": "iOS/10.3"
|
||||||
|
},
|
||||||
|
"name": "get token (setup)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"variables": {
|
||||||
|
"token": "$session_token"
|
||||||
|
},
|
||||||
|
"api": "api/reset_all.yml",
|
||||||
|
"name": "reset all users"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
43
tests/testcases/setup.v2.json
Normal file
43
tests/testcases/setup.v2.json
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "setup and reset all.",
|
||||||
|
"base_url": "http://127.0.0.1:5000",
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "TESTCASE_SETUP_XXX",
|
||||||
|
"app_version": "2.8.6",
|
||||||
|
"os_platform": "ios",
|
||||||
|
"user_agent": "iOS/10.3"
|
||||||
|
},
|
||||||
|
"id": "setup_and_reset",
|
||||||
|
"verify": false,
|
||||||
|
"output": [
|
||||||
|
"session_token"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "get token (setup)",
|
||||||
|
"api": "api/get_token.yml",
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "$device_sn",
|
||||||
|
"app_version": "2.8.6",
|
||||||
|
"os_platform": "ios",
|
||||||
|
"user_agent": "iOS/10.3"
|
||||||
|
},
|
||||||
|
"extract": [
|
||||||
|
{"session_token": "content.token"}
|
||||||
|
],
|
||||||
|
"validate": [
|
||||||
|
{"eq": ["status_code", 200]},
|
||||||
|
{"len_eq": ["content.token", 16]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "reset all users",
|
||||||
|
"api": "api/reset_all.yml",
|
||||||
|
"variables": {
|
||||||
|
"token": "$session_token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
32
tests/testcases/setup.v2.yml
Normal file
32
tests/testcases/setup.v2.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
config:
|
||||||
|
name: "setup and reset all."
|
||||||
|
id: setup_and_reset
|
||||||
|
variables:
|
||||||
|
user_agent: 'iOS/10.3'
|
||||||
|
device_sn: "TESTCASE_SETUP_XXX"
|
||||||
|
os_platform: 'ios'
|
||||||
|
app_version: '2.8.6'
|
||||||
|
base_url: "http://127.0.0.1:5000"
|
||||||
|
verify: False
|
||||||
|
output:
|
||||||
|
- session_token
|
||||||
|
|
||||||
|
teststeps:
|
||||||
|
-
|
||||||
|
name: get token (setup)
|
||||||
|
api: api/get_token.yml
|
||||||
|
variables:
|
||||||
|
user_agent: 'iOS/10.3'
|
||||||
|
device_sn: $device_sn
|
||||||
|
os_platform: 'ios'
|
||||||
|
app_version: '2.8.6'
|
||||||
|
extract:
|
||||||
|
- session_token: content.token
|
||||||
|
validate:
|
||||||
|
- eq: ["status_code", 200]
|
||||||
|
- len_eq: ["content.token", 16]
|
||||||
|
-
|
||||||
|
name: reset all users
|
||||||
|
api: api/reset_all.yml
|
||||||
|
variables:
|
||||||
|
token: $session_token
|
||||||
29
tests/testsuites/create_users.json
Normal file
29
tests/testsuites/create_users.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"testcases": {
|
||||||
|
"create user 1001 and check result.": {
|
||||||
|
"testcase": "testcases/create_user.yml",
|
||||||
|
"variables": {
|
||||||
|
"var_d": "$var_c",
|
||||||
|
"var_c": "${gen_random_string(5)}",
|
||||||
|
"uid": 1001
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"create user 1000 and check result.": {
|
||||||
|
"testcase": "testcases/create_user.yml",
|
||||||
|
"variables": {
|
||||||
|
"var_d": "$var_c",
|
||||||
|
"var_c": "${gen_random_string(5)}",
|
||||||
|
"uid": 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "${gen_random_string(15)}",
|
||||||
|
"var_b": "$var_a",
|
||||||
|
"var_a": "${gen_random_string(5)}"
|
||||||
|
},
|
||||||
|
"name": "create users with uid",
|
||||||
|
"base_url": "http://127.0.0.1:5000"
|
||||||
|
}
|
||||||
|
}
|
||||||
31
tests/testsuites/create_users.v2.json
Normal file
31
tests/testsuites/create_users.v2.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "${gen_random_string(15)}",
|
||||||
|
"var_b": "$var_a",
|
||||||
|
"var_a": "${gen_random_string(5)}"
|
||||||
|
},
|
||||||
|
"name": "create users with uid",
|
||||||
|
"base_url": "http://127.0.0.1:5000"
|
||||||
|
},
|
||||||
|
"testcases": [
|
||||||
|
{
|
||||||
|
"name": "create user 1000 and check result.",
|
||||||
|
"testcase": "testcases/create_user.yml",
|
||||||
|
"variables": {
|
||||||
|
"var_d": "$var_c",
|
||||||
|
"var_c": "${gen_random_string(5)}",
|
||||||
|
"uid": 1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "create user 1001 and check result.",
|
||||||
|
"testcase": "testcases/create_user.yml",
|
||||||
|
"variables": {
|
||||||
|
"var_d": "$var_c",
|
||||||
|
"var_c": "${gen_random_string(5)}",
|
||||||
|
"uid": 1001
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
24
tests/testsuites/create_users.v2.yml
Normal file
24
tests/testsuites/create_users.v2.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
config:
|
||||||
|
name: create users with uid
|
||||||
|
variables:
|
||||||
|
device_sn: ${gen_random_string(15)}
|
||||||
|
var_a: ${gen_random_string(5)}
|
||||||
|
var_b: $var_a
|
||||||
|
base_url: "http://127.0.0.1:5000"
|
||||||
|
|
||||||
|
testcases:
|
||||||
|
-
|
||||||
|
name: create user 1000 and check result.
|
||||||
|
testcase: testcases/create_user.yml
|
||||||
|
variables:
|
||||||
|
uid: 1000
|
||||||
|
var_c: ${gen_random_string(5)}
|
||||||
|
var_d: $var_c
|
||||||
|
|
||||||
|
-
|
||||||
|
name: create user 1001 and check result.
|
||||||
|
testcase: testcases/create_user.yml
|
||||||
|
variables:
|
||||||
|
uid: 1001
|
||||||
|
var_c: ${gen_random_string(5)}
|
||||||
|
var_d: $var_c
|
||||||
Reference in New Issue
Block a user