From da166f0c55c17d1c79f857438ce10aff3b3a53d8 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 24 Jun 2019 14:25:33 +0800 Subject: [PATCH 1/5] add wheel --- Pipfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Pipfile b/Pipfile index 5e4c9ad5..bee6c544 100644 --- a/Pipfile +++ b/Pipfile @@ -20,5 +20,6 @@ coveralls = "*" twine = "*" contextlib2 = "*" locustio = "*" +wheel = "*" [scripts] From ec384dc9da973313a98756520e307f55f9ef5538 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 24 Jun 2019 16:09:10 +0800 Subject: [PATCH 2/5] feat: testcase in format version 2 --- httprunner/__about__.py | 2 +- httprunner/loader.py | 47 ++++++++++++++++++++++++++++ tests/test_loader.py | 29 ++++++++++++----- tests/testcases/setup.json | 59 +++++++++++++++++++++++++++++++++++ tests/testcases/setup.v2.json | 43 +++++++++++++++++++++++++ tests/testcases/setup.v2.yml | 32 +++++++++++++++++++ 6 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 tests/testcases/setup.json create mode 100644 tests/testcases/setup.v2.json create mode 100644 tests/testcases/setup.v2.yml diff --git a/httprunner/__about__.py b/httprunner/__about__.py index 74d0888b..e3bd235e 100644 --- a/httprunner/__about__.py +++ b/httprunner/__about__.py @@ -1,7 +1,7 @@ __title__ = 'HttpRunner' __description__ = 'One-stop solution for HTTP(S) testing.' __url__ = 'https://github.com/HttpRunner/HttpRunner' -__version__ = '2.1.3' +__version__ = '2.2.0' __author__ = 'debugtalk' __author_email__ = 'mail@debugtalk.com' __license__ = 'Apache-2.0' diff --git a/httprunner/loader.py b/httprunner/loader.py index 3fddb238..35e8b4d7 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -442,6 +442,44 @@ def load_testcase(raw_testcase): } +def load_testcase_v2(raw_testcase): + """ load testcase in 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): """ load testsuite with testcase references. @@ -523,18 +561,27 @@ def load_test_file(path): loaded_content = load_testsuite(raw_content) loaded_content["path"] = path 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: # file_type: api # TODO: add json schema validation for api loaded_content = raw_content loaded_content["path"] = path loaded_content["type"] = "api" + else: # invalid format logger.log_warning("Invalid test file format: {}".format(path)) elif isinstance(raw_content, list) and len(raw_content) > 0: # file_type: testcase + # make compatible with version < 2.2.0 # TODO: add json schema validation for testcase loaded_content = load_testcase(raw_content) loaded_content["path"] = path diff --git a/tests/test_loader.py b/tests/test_loader.py index 97845ddd..b9d46f1d 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -292,13 +292,28 @@ class TestSuiteLoader(unittest.TestCase): self.assertEqual(loaded_content["request"]["url"], "/api/users/$uid") def test_load_test_file_testcase(self): - loaded_content = loader.load_test_file("tests/testcases/setup.yml") - 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) + for loaded_content in [ + loader.load_test_file("tests/testcases/setup.yml"), + loader.load_test_file("tests/testcases/setup.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_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): loaded_content = loader.load_test_file("tests/testsuites/create_users.yml") diff --git a/tests/testcases/setup.json b/tests/testcases/setup.json new file mode 100644 index 00000000..d8690447 --- /dev/null +++ b/tests/testcases/setup.json @@ -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" + } + } +] \ No newline at end of file diff --git a/tests/testcases/setup.v2.json b/tests/testcases/setup.v2.json new file mode 100644 index 00000000..bbc2d3ed --- /dev/null +++ b/tests/testcases/setup.v2.json @@ -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" + } + } + ] +} \ No newline at end of file diff --git a/tests/testcases/setup.v2.yml b/tests/testcases/setup.v2.yml new file mode 100644 index 00000000..3cf58c1d --- /dev/null +++ b/tests/testcases/setup.v2.yml @@ -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 From eb1729e88a9a288eb67995a0333c088eb43c1381 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 24 Jun 2019 16:45:49 +0800 Subject: [PATCH 3/5] feat: testsuite in format version 2 --- httprunner/loader.py | 44 ++++++++++++++++++++++----- tests/test_loader.py | 39 ++++++++++++++++++------ tests/testsuites/create_users.json | 29 ++++++++++++++++++ tests/testsuites/create_users.v2.json | 31 +++++++++++++++++++ tests/testsuites/create_users.v2.yml | 24 +++++++++++++++ 5 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 tests/testsuites/create_users.json create mode 100644 tests/testsuites/create_users.v2.json create mode 100644 tests/testsuites/create_users.v2.yml diff --git a/httprunner/loader.py b/httprunner/loader.py index 35e8b4d7..9b48991c 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -443,7 +443,7 @@ def load_testcase(raw_testcase): def load_testcase_v2(raw_testcase): - """ load testcase in version 2. + """ load testcase in format version 2. Args: raw_testcase (dict): raw testcase content loaded from JSON/YAML file: @@ -482,13 +482,15 @@ def load_testcase_v2(raw_testcase): def load_testsuite(raw_testsuite): """ load testsuite with testcase references. + support two different formats. Args: raw_testsuite (dict): raw testsuite content loaded from JSON/YAML file: + # version 1, compatible with version < 2.2.0 { "config": { - "name": "", - "request": {} + "name": "xxx", + "variables": {} } "testcases": { "testcase1": { @@ -500,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: dict: loaded testsuite content { @@ -508,10 +527,21 @@ def load_testsuite(raw_testsuite): } """ - testcases = raw_testsuite["testcases"] - for name, raw_testcase in testcases.items(): - __extend_with_testcase_ref(raw_testcase) - raw_testcase.setdefault("name", name) + raw_testcases = raw_testsuite.pop("testcases") + raw_testsuite["testcases"] = {} + + 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 return raw_testsuite diff --git a/tests/test_loader.py b/tests/test_loader.py index b9d46f1d..b7ffbe27 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -316,17 +316,36 @@ class TestSuiteLoader(unittest.TestCase): self.assertEqual(len(loaded_content["teststeps"]), 2) def test_load_test_file_testsuite(self): - loaded_content = loader.load_test_file("tests/testsuites/create_users.yml") - self.assertEqual(loaded_content["type"], "testsuite") + for loaded_content in [ + 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"] - 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." - ) + 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_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): path = os.path.join( diff --git a/tests/testsuites/create_users.json b/tests/testsuites/create_users.json new file mode 100644 index 00000000..d504c99f --- /dev/null +++ b/tests/testsuites/create_users.json @@ -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" + } +} \ No newline at end of file diff --git a/tests/testsuites/create_users.v2.json b/tests/testsuites/create_users.v2.json new file mode 100644 index 00000000..de4d5d27 --- /dev/null +++ b/tests/testsuites/create_users.v2.json @@ -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 + } + } + ] +} \ No newline at end of file diff --git a/tests/testsuites/create_users.v2.yml b/tests/testsuites/create_users.v2.yml new file mode 100644 index 00000000..0714d82f --- /dev/null +++ b/tests/testsuites/create_users.v2.yml @@ -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 From 0e0716a682049050a2952ae1d5fce96157d9ffd0 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 24 Jun 2019 17:01:54 +0800 Subject: [PATCH 4/5] fix: handle test file format error --- httprunner/loader.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/httprunner/loader.py b/httprunner/loader.py index 9b48991c..4093bb37 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -536,6 +536,7 @@ def load_testsuite(raw_testsuite): __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: @@ -543,6 +544,10 @@ def load_testsuite(raw_testsuite): testcase_name = raw_testcase["name"] raw_testsuite["testcases"][testcase_name] = raw_testcase + else: + # invalid format + raise exceptions.FileFormatError("Invalid testsuite format!") + return raw_testsuite @@ -607,7 +612,7 @@ def load_test_file(path): else: # 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: # file_type: testcase @@ -619,7 +624,7 @@ def load_test_file(path): else: # invalid format - logger.log_warning("Invalid test file format: {}".format(path)) + raise exceptions.FileFormatError("Invalid test file format!") return loaded_content @@ -853,7 +858,11 @@ def load_tests(path, dot_env_path=None): } 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: pass elif loaded_content["type"] == "testsuite": From 8afce9da67454404f7939fb886210d4cbd346efd Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 24 Jun 2019 22:02:49 +0800 Subject: [PATCH 5/5] update changelog 2.2.0 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96f7da32..582d216e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # 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) **Bugfixes**