diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 6064459e..4948e7cf 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -24,7 +24,7 @@ jobs: python -m pip install --upgrade pip pip install poetry poetry --version - poetry install -vv + poetry install -vv -E upload - name: Test package installation run: | poetry build @@ -36,7 +36,7 @@ jobs: httprunner har2case -h - name: Run smoketest - postman echo run: | - hrun -s examples/postman_echo/request_methods + poetry run hrun examples/postman_echo/request_methods - name: Run smoketest - httpbin run: | - hrun -s examples/httpbin/ + poetry run hrun examples/httpbin/ diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9c736212..5ad8d360 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,26 @@ # Release History +## 3.0.7 (2020-06-03) + +**Added** + +- feat: make pytest files in chain style +- feat: `hrun` supports run pytest files +- feat: get raw testcase model from pytest file + +**Fixed** + +- fix: convert jmespath.search result to int/float unintentionally +- fix: referenced testcase should not be run duplicately +- fix: requests.cookies.CookieConflictError, multiple cookies with name +- fix: missing exit code from pytest +- fix: skip invalid testcase/testsuite yaml/json file + +**Changed** + +- change: `har2case` generate pytest file by default +- docs: update sponsor info + ## 3.0.6 (2020-05-29) **Added** diff --git a/examples/httpbin/__init__.py b/examples/httpbin/__init__.py new file mode 100644 index 00000000..70cfba53 --- /dev/null +++ b/examples/httpbin/__init__.py @@ -0,0 +1 @@ +# NOTICE: Generated By HttpRunner. DO NOT EDIT! diff --git a/examples/httpbin/basic_test.py b/examples/httpbin/basic_test.py index 91ffac52..37741c07 100644 --- a/examples/httpbin/basic_test.py +++ b/examples/httpbin/basic_test.py @@ -1,105 +1,76 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/httpbin/basic.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseBasic(HttpRunner): - config = TConfig( - **{ - "name": "basic test with httpbin", - "base_url": "https://httpbin.org/", - "path": "examples/httpbin/basic_test.py", - "variables": {}, - } - ) + config = Config("basic test with httpbin").base_url("https://httpbin.org/") teststeps = [ - TStep( - **{ - "name": "headers", - "request": {"url": "/headers", "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.headers.Host", "httpbin.org"]}, - ], - } + Step( + RunRequest("headers") + .get("/headers") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.headers.Host", "httpbin.org") ), - TStep( - **{ - "name": "user-agent", - "request": {"url": "/user-agent", "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"startswith": ['body."user-agent"', "python-requests"]}, - ], - } + Step( + RunRequest("user-agent") + .get("/user-agent") + .validate() + .assert_equal("status_code", 200) + .assert_startswith('body."user-agent"', "python-requests") ), - TStep( - **{ - "name": "get without params", - "request": {"url": "/get", "method": "GET"}, - "validate": [{"eq": ["status_code", 200]}, {"eq": ["body.args", {}]}], - } + Step( + RunRequest("get without params") + .get("/get") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args", {}) ), - TStep( - **{ - "name": "get with params in url", - "request": {"url": "/get?a=1&b=2", "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args", {"a": "1", "b": "2"}]}, - ], - } + Step( + RunRequest("get with params in url") + .get("/get?a=1&b=2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args", {"a": "1", "b": "2"}) ), - TStep( - **{ - "name": "get with params in params field", - "request": {"url": "/get", "params": {"a": 1, "b": 2}, "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args", {"a": "1", "b": "2"}]}, - ], - } + Step( + RunRequest("get with params in params field") + .get("/get") + .with_params(**{"a": 1, "b": 2}) + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args", {"a": "1", "b": "2"}) ), - TStep( - **{ - "name": "set cookie", - "request": {"url": "/cookies/set?name=value", "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.cookies.name", "value"]}, - ], - } + Step( + RunRequest("set cookie") + .get("/cookies/set?name=value") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.cookies.name", "value") ), - TStep( - **{ - "name": "extract cookie", - "request": {"url": "/cookies", "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.cookies.name", "value"]}, - ], - } + Step( + RunRequest("extract cookie") + .get("/cookies") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.cookies.name", "value") ), - TStep( - **{ - "name": "post data", - "request": { - "url": "/post", - "method": "POST", - "headers": {"Content-Type": "application/json"}, - "data": "abc", - }, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("post data") + .post("/post") + .with_headers(**{"Content-Type": "application/json"}) + .with_data("abc") + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "validate body length", - "request": {"url": "/spec.json", "method": "GET"}, - "validate": [{"len_eq": ["body", 9]}], - } + Step( + RunRequest("validate body length") + .get("/spec.json") + .validate() + .assert_length_equal("body", 9) ), ] diff --git a/examples/httpbin/hooks_test.py b/examples/httpbin/hooks_test.py index 0e86ee6b..01ebf292 100644 --- a/examples/httpbin/hooks_test.py +++ b/examples/httpbin/hooks_test.py @@ -1,48 +1,27 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/httpbin/hooks.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseHooks(HttpRunner): - config = TConfig( - **{ - "name": "basic test with httpbin", - "base_url": "${get_httpbin_server()}", - "setup_hooks": ["${hook_print(setup)}"], - "teardown_hooks": ["${hook_print(teardown)}"], - "path": "examples/httpbin/hooks_test.py", - "variables": {}, - } - ) + config = Config("basic test with httpbin").base_url("${get_httpbin_server()}") teststeps = [ - TStep( - **{ - "name": "headers", - "variables": {"a": 123}, - "request": {"url": "/headers", "method": "GET"}, - "setup_hooks": [ - "${setup_hook_add_kwargs($request)}", - "${setup_hook_remove_kwargs($request)}", - ], - "teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 1)}"], - "validate": [ - {"eq": ["status_code", 200]}, - {"contained_by": ["body.headers.Host", "${get_httpbin_server()}"]}, - ], - } + Step( + RunRequest("headers") + .with_variables(**{"a": 123}) + .get("/headers") + .validate() + .assert_equal("status_code", 200) + .assert_contained_by("body.headers.Host", "${get_httpbin_server()}") ), - TStep( - **{ - "name": "alter response", - "request": {"url": "/headers", "method": "GET"}, - "teardown_hooks": ["${alter_response($response)}"], - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.headers.Host", "httpbin.org"]}, - ], - } + Step( + RunRequest("alter response") + .get("/headers") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.headers.Host", "httpbin.org") ), ] diff --git a/examples/httpbin/load_image_test.py b/examples/httpbin/load_image_test.py index 2e69653d..9e36a4f8 100644 --- a/examples/httpbin/load_image_test.py +++ b/examples/httpbin/load_image_test.py @@ -1,47 +1,36 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/httpbin/load_image.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseLoadImage(HttpRunner): - config = TConfig( - **{ - "name": "load images", - "base_url": "${get_httpbin_server()}", - "path": "examples/httpbin/load_image_test.py", - "variables": {}, - } - ) + config = Config("load images").base_url("${get_httpbin_server()}") teststeps = [ - TStep( - **{ - "name": "get png image", - "request": {"url": "/image/png", "method": "GET"}, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("get png image") + .get("/image/png") + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "get jpeg image", - "request": {"url": "/image/jpeg", "method": "GET"}, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("get jpeg image") + .get("/image/jpeg") + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "get webp image", - "request": {"url": "/image/webp", "method": "GET"}, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("get webp image") + .get("/image/webp") + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "get svg image", - "request": {"url": "/image/svg", "method": "GET"}, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("get svg image") + .get("/image/svg") + .validate() + .assert_equal("status_code", 200) ), ] diff --git a/examples/httpbin/upload_test.py b/examples/httpbin/upload_test.py index 986b3746..64dfcdbd 100644 --- a/examples/httpbin/upload_test.py +++ b/examples/httpbin/upload_test.py @@ -1,54 +1,35 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/httpbin/upload.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseUpload(HttpRunner): - config = TConfig( - **{ - "name": "test upload file with httpbin", - "base_url": "${get_httpbin_server()}", - "path": "examples/httpbin/upload_test.py", - "variables": {}, - } - ) + config = Config("test upload file with httpbin").base_url("${get_httpbin_server()}") teststeps = [ - TStep( - **{ - "name": "upload file", - "variables": { + Step( + RunRequest("upload file") + .with_variables( + **{ "file_path": "test.env", "m_encoder": "${multipart_encoder(file=$file_path)}", - }, - "request": { - "url": "/post", - "method": "POST", - "headers": { - "Content-Type": "${multipart_content_type($m_encoder)}" - }, - "data": "$m_encoder", - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"startswith": ["body.files.file", "UserName=test"]}, - ], - } + } + ) + .post("/post") + .with_headers(**{"Content-Type": "${multipart_content_type($m_encoder)}"}) + .with_data("$m_encoder") + .validate() + .assert_equal("status_code", 200) + .assert_startswith("body.files.file", "UserName=test") ), - TStep( - **{ - "name": "upload file with keyword", - "request": { - "url": "/post", - "method": "POST", - "upload": {"file": "test.env"}, - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"startswith": ["body.files.file", "UserName=test"]}, - ], - } + Step( + RunRequest("upload file with keyword") + .post("/post") + .upload(**{"file": "test.env"}) + .validate() + .assert_equal("status_code", 200) + .assert_startswith("body.files.file", "UserName=test") ), ] diff --git a/examples/httpbin/validate.yml b/examples/httpbin/validate.yml index c45e2ffd..d5769a7b 100644 --- a/examples/httpbin/validate.yml +++ b/examples/httpbin/validate.yml @@ -13,8 +13,8 @@ teststeps: method: GET validate: - eq: ["status_code", 200] - - eq: ["body.args.a", 1] - - eq: ["body.args.b", 2] + - eq: ["body.args.a", "1"] + - eq: ["body.args.b", "2"] validate_script: - "assert status_code == 200" diff --git a/examples/httpbin/validate_test.py b/examples/httpbin/validate_test.py index fdf2c8a4..c6ae7099 100644 --- a/examples/httpbin/validate_test.py +++ b/examples/httpbin/validate_test.py @@ -1,43 +1,28 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/httpbin/validate.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseValidate(HttpRunner): - config = TConfig( - **{ - "name": "basic test with httpbin", - "base_url": "http://httpbin.org/", - "path": "examples/httpbin/validate_test.py", - "variables": {}, - } - ) + config = Config("basic test with httpbin").base_url("http://httpbin.org/") teststeps = [ - TStep( - **{ - "name": "validate response with json path", - "request": {"url": "/get", "params": {"a": 1, "b": 2}, "method": "GET"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.a", 1]}, - {"eq": ["body.args.b", 2]}, - ], - "validate_script": ["assert status_code == 200"], - } + Step( + RunRequest("validate response with json path") + .get("/get") + .with_params(**{"a": 1, "b": 2}) + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args.a", "1") + .assert_equal("body.args.b", "2") ), - TStep( - **{ - "name": "validate response with python script", - "request": {"url": "/get", "params": {"a": 1, "b": 2}, "method": "GET"}, - "validate": [{"eq": ["status_code", 200]}], - "validate_script": [ - "assert status_code == 201", - "a = response_json.get('args').get('a')", - "assert a == '1'", - ], - } + Step( + RunRequest("validate response with python script") + .get("/get") + .with_params(**{"a": 1, "b": 2}) + .validate() + .assert_equal("status_code", 200) ), ] diff --git a/examples/postman_echo/cookie_manipulation/__init__.py b/examples/postman_echo/cookie_manipulation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/postman_echo/cookie_manipulation/hardcode.yml b/examples/postman_echo/cookie_manipulation/hardcode.yml new file mode 100644 index 00000000..f81c5f7c --- /dev/null +++ b/examples/postman_echo/cookie_manipulation/hardcode.yml @@ -0,0 +1,34 @@ +config: + name: "set & delete cookies." + base_url: "https://postman-echo.com" + verify: False + export: ["cookie_foo1", "cookie_foo3"] + +teststeps: +- + name: set cookie foo1 & foo2 & foo3 + request: + method: GET + url: /cookies/set + params: + foo1: bar1 + foo2: bar2 + headers: + User-Agent: HttpRunner/${get_httprunner_version()} + extract: + cookie_foo1: $.cookies.foo1 + validate: + - eq: ["status_code", 200] + - eq: ["cookies.foo1", "bar1"] +- + name: delete cookie foo2 + request: + method: GET + url: /cookies/delete?foo2 + headers: + User-Agent: HttpRunner/${get_httprunner_version()} + validate: + - eq: ["status_code", 200] + - ne: ["$.cookies.foo1", "$foo1"] + - eq: ["$.cookies.foo1", "$cookie_foo1"] + - eq: ["$.cookies.foo3", "$cookie_foo3"] diff --git a/examples/postman_echo/cookie_manipulation/hardcode_test.py b/examples/postman_echo/cookie_manipulation/hardcode_test.py new file mode 100644 index 00000000..000d0404 --- /dev/null +++ b/examples/postman_echo/cookie_manipulation/hardcode_test.py @@ -0,0 +1,54 @@ +# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# FROM: examples/postman_echo/cookie_manipulation/hardcode.yml +from httprunner import HttpRunner, TConfig, TStep + + +class TestCaseHardcode(HttpRunner): + config = TConfig( + **{ + "name": "set & delete cookies.", + "base_url": "https://postman-echo.com", + "verify": False, + "export": ["cookie_foo1", "cookie_foo3"], + "path": "examples/postman_echo/cookie_manipulation/hardcode_test.py", + } + ) + + teststeps = [ + TStep( + **{ + "name": "set cookie foo1 & foo2 & foo3", + "request": { + "method": "GET", + "url": "/cookies/set", + "params": {"foo1": "bar1", "foo2": "bar2"}, + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "extract": {"cookie_foo1": "$.cookies.foo1"}, + "validate": [ + {"eq": ["status_code", 200]}, + {"eq": ["cookies.foo1", "bar1"]}, + ], + } + ), + TStep( + **{ + "name": "delete cookie foo2", + "request": { + "method": "GET", + "url": "/cookies/delete?foo2", + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "validate": [ + {"eq": ["status_code", 200]}, + {"ne": ["$.cookies.foo1", "$foo1"]}, + {"eq": ["$.cookies.foo1", "$cookie_foo1"]}, + {"eq": ["$.cookies.foo3", "$cookie_foo3"]}, + ], + } + ), + ] + + +if __name__ == "__main__": + TestCaseHardcode().test_start() diff --git a/examples/postman_echo/cookie_manipulation/set_delete_cookies.py b/examples/postman_echo/cookie_manipulation/set_delete_cookies.py new file mode 100644 index 00000000..b2e3bf26 --- /dev/null +++ b/examples/postman_echo/cookie_manipulation/set_delete_cookies.py @@ -0,0 +1,62 @@ +import unittest +import requests + +from httprunner.runner import HttpRunner +from httprunner.schema import TConfig, TStep + + +class TestCaseSetDeleteCookies(unittest.TestCase): + config = TConfig( + **{ + "name": "set & delete cookies.", + "base_url": "https://postman-echo.com", + "variables": {"foo1": "bar1", "foo2": "bar2"}, + "verify": False, + "export": ["cookie_foo1", "cookie_foo3"], + } + ) + + teststeps = [ + TStep( + **{ + "name": "set cookie foo1 & foo2 & foo3", + "variables": {"foo3": "bar3"}, + "request": { + "method": "GET", + "url": "/cookies/set", + "params": {"foo1": "bar111", "foo2": "$foo2", "foo3": "$foo3"}, + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "extract": { + "cookie_foo1": "$.cookies.foo1", + "cookie_foo3": "$.cookies.foo3", + }, + "validate": [ + {"eq": ["status_code", 200]}, + {"eq": ["$.cookies.foo3", "$foo3"]}, + ], + } + ), + TStep( + **{ + "name": "delete cookie foo2", + "request": { + "method": "GET", + "url": "/cookies/delete?foo2", + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "validate": [ + {"eq": ["status_code", 200]}, + {"ne": ["$.cookies.foo1", "$foo1"]}, + {"eq": ["$.cookies.foo1", "$cookie_foo1"]}, + {"eq": ["$.cookies.foo3", "$cookie_foo3"]}, + ], + } + ), + ] + + def test_start(self): + s = requests.Session() + HttpRunner(self.config, self.teststeps, session=s).with_variables( + foo1="bar123", foo2="bar22" + ).run() diff --git a/examples/postman_echo/cookie_manipulation/set_delete_cookies_test.py b/examples/postman_echo/cookie_manipulation/set_delete_cookies_test.py new file mode 100644 index 00000000..540a2eb1 --- /dev/null +++ b/examples/postman_echo/cookie_manipulation/set_delete_cookies_test.py @@ -0,0 +1,59 @@ +# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# FROM: examples/postman_echo/cookie_manipulation/set_delete_cookies.yml +from httprunner import HttpRunner, TConfig, TStep + + +class TestCaseSetDeleteCookies(HttpRunner): + config = TConfig( + **{ + "name": "set & delete cookies.", + "variables": {"foo1": "bar1", "foo2": "bar2"}, + "base_url": "https://postman-echo.com", + "verify": False, + "export": ["cookie_foo1", "cookie_foo3"], + "path": "examples/postman_echo/cookie_manipulation/set_delete_cookies_test.py", + } + ) + + teststeps = [ + TStep( + **{ + "name": "set cookie foo1 & foo2 & foo3", + "variables": {"foo3": "bar3"}, + "request": { + "method": "GET", + "url": "/cookies/set", + "params": {"foo1": "bar111", "foo2": "$foo2", "foo3": "$foo3"}, + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "extract": { + "cookie_foo1": "$.cookies.foo1", + "cookie_foo3": "$.cookies.foo3", + }, + "validate": [ + {"eq": ["status_code", 200]}, + {"ne": ["$.cookies.foo3", "$foo3"]}, + ], + } + ), + TStep( + **{ + "name": "delete cookie foo2", + "request": { + "method": "GET", + "url": "/cookies/delete?foo2", + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "validate": [ + {"eq": ["status_code", 200]}, + {"ne": ["$.cookies.foo1", "$foo1"]}, + {"eq": ["$.cookies.foo1", "$cookie_foo1"]}, + {"eq": ["$.cookies.foo3", "$cookie_foo3"]}, + ], + } + ), + ] + + +if __name__ == "__main__": + TestCaseSetDeleteCookies().test_start() diff --git a/examples/postman_echo/request_methods/conftest.py b/examples/postman_echo/request_methods/conftest.py index 4f0e444c..788c2686 100644 --- a/examples/postman_echo/request_methods/conftest.py +++ b/examples/postman_echo/request_methods/conftest.py @@ -2,10 +2,9 @@ import uuid from typing import List import pytest +from httprunner import Config, Step from loguru import logger -from httprunner.schema import TConfig, TStep - @pytest.fixture(scope="session", autouse=True) def session_fixture(request): @@ -33,8 +32,8 @@ def session_fixture(request): @pytest.fixture(scope="function", autouse=True) def testcase_fixture(request): """setup and teardown each testcase""" - config: TConfig = request.cls.config - teststeps: List[TStep] = request.cls.teststeps + config: Config = request.cls.config + teststeps: List[Step] = request.cls.teststeps logger.debug(f"setup testcase fixture: {config.name} - {request.module.__name__}") diff --git a/examples/postman_echo/request_methods/demo_testsuite_yml/__init__.py b/examples/postman_echo/request_methods/demo_testsuite_yml/__init__.py new file mode 100644 index 00000000..70cfba53 --- /dev/null +++ b/examples/postman_echo/request_methods/demo_testsuite_yml/__init__.py @@ -0,0 +1 @@ +# NOTICE: Generated By HttpRunner. DO NOT EDIT! diff --git a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py index 5c8647f8..323fb401 100644 --- a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py +++ b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py @@ -1,87 +1,69 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/request_with_functions.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithFunctions(HttpRunner): - config = TConfig( - **{ - "name": "request with functions", - "variables": {"foo1": "session_bar1", "var1": "testsuite_val1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py", - } + config = ( + Config("request with functions") + .variables(**{"foo1": "session_bar1", "var1": "testsuite_val1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "variables": { - "foo1": "bar1", - "foo2": "session_bar2", - "sum_v": "${sum_two(1, 2)}", - }, - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}, - "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, - }, - "extract": {"session_foo2": "body.args.foo2"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.foo1", "session_bar1"]}, - {"eq": ["body.args.sum_v", 3]}, - {"eq": ["body.args.foo2", "session_bar2"]}, - ], - } + Step( + RunRequest("get with params") + .with_variables( + **{"foo1": "bar1", "foo2": "session_bar2", "sum_v": "${sum_two(1, 2)}"} + ) + .get("/get") + .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}) + .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"}) + .extract() + .with_jmespath("body.args.foo2", "session_foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args.foo1", "session_bar1") + .assert_equal("body.args.sum_v", "3") + .assert_equal("body.args.foo2", "session_bar2") ), - TStep( - **{ - "name": "post raw text", - "variables": {"foo1": "hello world", "foo3": "$session_foo2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/${get_httprunner_version()}", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body: $foo1-$foo3.", - }, - "validate": [ - {"eq": ["status_code", 200]}, - { - "eq": [ - "body.data", - "This is expected to be sent back as part of response body: session_bar1-session_bar2.", - ] - }, - ], - } + Step( + RunRequest("post raw text") + .with_variables(**{"foo1": "hello world", "foo3": "$session_foo2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/${get_httprunner_version()}", + "Content-Type": "text/plain", + } + ) + .with_data( + "This is expected to be sent back as part of response body: $foo1-$foo3." + ) + .validate() + .assert_equal("status_code", 200) + .assert_equal( + "body.data", + "This is expected to be sent back as part of response body: session_bar1-session_bar2.", + ) ), - TStep( - **{ - "name": "post form data", - "variables": {"foo1": "bar1", "foo2": "bar2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/${get_httprunner_version()}", - "Content-Type": "application/x-www-form-urlencoded", - }, - "data": "foo1=$foo1&foo2=$foo2", - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.form.foo1", "session_bar1"]}, - {"eq": ["body.form.foo2", "bar2"]}, - ], - } + Step( + RunRequest("post form data") + .with_variables(**{"foo1": "bar1", "foo2": "bar2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/${get_httprunner_version()}", + "Content-Type": "application/x-www-form-urlencoded", + } + ) + .with_data("foo1=$foo1&foo2=$foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.form.foo1", "session_bar1") + .assert_equal("body.form.foo2", "bar2") ), ] diff --git a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py index 187b5e23..01547709 100644 --- a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py +++ b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py @@ -1,4 +1,4 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml import os @@ -6,7 +6,7 @@ import sys sys.path.insert(0, os.getcwd()) -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase from examples.postman_echo.request_methods.request_with_functions_test import ( TestCaseRequestWithFunctions as RequestWithFunctions, @@ -14,23 +14,18 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( class TestCaseRequestWithTestcaseReference(HttpRunner): - config = TConfig( - **{ - "name": "request with referenced testcase", - "variables": {"foo1": "session_bar1", "var2": "testsuite_val2"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py", - } + config = ( + Config("request with referenced testcase") + .variables(**{"foo1": "session_bar1", "var2": "testsuite_val2"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "request with functions", - "variables": {"foo1": "override_bar1"}, - "testcase": RequestWithFunctions, - } + Step( + RunTestCase("request with functions") + .with_variables(**{"foo1": "override_bar1"}) + .call(RequestWithFunctions) ), ] diff --git a/examples/postman_echo/request_methods/hardcode_test.py b/examples/postman_echo/request_methods/hardcode_test.py index f9931709..3d30e666 100644 --- a/examples/postman_echo/request_methods/hardcode_test.py +++ b/examples/postman_echo/request_methods/hardcode_test.py @@ -1,77 +1,57 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/hardcode.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseHardcode(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase in hardcode", - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/hardcode_test.py", - "variables": {}, - } + config = ( + Config("request methods testcase in hardcode") + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "bar1", "foo2": "bar2"}, - "headers": {"User-Agent": "HttpRunner/3.0"}, - }, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("get with params") + .get("/get") + .with_params(**{"foo1": "bar1", "foo2": "bar2"}) + .with_headers(**{"User-Agent": "HttpRunner/3.0"}) + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "post raw text", - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body.", - }, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("post raw text") + .post("/post") + .with_headers( + **{"User-Agent": "HttpRunner/3.0", "Content-Type": "text/plain"} + ) + .with_data("This is expected to be sent back as part of response body.") + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "post form data", - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "application/x-www-form-urlencoded", - }, - "data": "foo1=bar1&foo2=bar2", - }, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("post form data") + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/3.0", + "Content-Type": "application/x-www-form-urlencoded", + } + ) + .with_data("foo1=bar1&foo2=bar2") + .validate() + .assert_equal("status_code", 200) ), - TStep( - **{ - "name": "put request", - "request": { - "method": "PUT", - "url": "/put", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body.", - }, - "validate": [{"eq": ["status_code", 200]}], - } + Step( + RunRequest("put request") + .put("/put") + .with_headers( + **{"User-Agent": "HttpRunner/3.0", "Content-Type": "text/plain"} + ) + .with_data("This is expected to be sent back as part of response body.") + .validate() + .assert_equal("status_code", 200) ), ] diff --git a/examples/postman_echo/request_methods/request_with_functions.yml b/examples/postman_echo/request_methods/request_with_functions.yml index 66a94ba4..6fc68325 100644 --- a/examples/postman_echo/request_methods/request_with_functions.yml +++ b/examples/postman_echo/request_methods/request_with_functions.yml @@ -26,7 +26,7 @@ teststeps: validate: - eq: ["status_code", 200] - eq: ["body.args.foo1", "session_bar1"] - - eq: ["body.args.sum_v", 3] + - eq: ["body.args.sum_v", "3"] - eq: ["body.args.foo2", "session_bar2"] - name: post raw text diff --git a/examples/postman_echo/request_methods/request_with_functions_test.py b/examples/postman_echo/request_methods/request_with_functions_test.py index 504b895a..279fa9ed 100644 --- a/examples/postman_echo/request_methods/request_with_functions_test.py +++ b/examples/postman_echo/request_methods/request_with_functions_test.py @@ -1,87 +1,69 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/request_with_functions.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithFunctions(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase with functions", - "variables": {"foo1": "session_bar1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/request_with_functions_test.py", - } + config = ( + Config("request methods testcase with functions") + .variables(**{"foo1": "session_bar1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "variables": { - "foo1": "bar1", - "foo2": "session_bar2", - "sum_v": "${sum_two(1, 2)}", - }, - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}, - "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, - }, - "extract": {"session_foo2": "body.args.foo2"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.foo1", "session_bar1"]}, - {"eq": ["body.args.sum_v", 3]}, - {"eq": ["body.args.foo2", "session_bar2"]}, - ], - } + Step( + RunRequest("get with params") + .with_variables( + **{"foo1": "bar1", "foo2": "session_bar2", "sum_v": "${sum_two(1, 2)}"} + ) + .get("/get") + .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}) + .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"}) + .extract() + .with_jmespath("body.args.foo2", "session_foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args.foo1", "session_bar1") + .assert_equal("body.args.sum_v", "3") + .assert_equal("body.args.foo2", "session_bar2") ), - TStep( - **{ - "name": "post raw text", - "variables": {"foo1": "hello world", "foo3": "$session_foo2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/${get_httprunner_version()}", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body: $foo1-$foo3.", - }, - "validate": [ - {"eq": ["status_code", 200]}, - { - "eq": [ - "body.data", - "This is expected to be sent back as part of response body: session_bar1-session_bar2.", - ] - }, - ], - } + Step( + RunRequest("post raw text") + .with_variables(**{"foo1": "hello world", "foo3": "$session_foo2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/${get_httprunner_version()}", + "Content-Type": "text/plain", + } + ) + .with_data( + "This is expected to be sent back as part of response body: $foo1-$foo3." + ) + .validate() + .assert_equal("status_code", 200) + .assert_equal( + "body.data", + "This is expected to be sent back as part of response body: session_bar1-session_bar2.", + ) ), - TStep( - **{ - "name": "post form data", - "variables": {"foo1": "bar1", "foo2": "bar2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/${get_httprunner_version()}", - "Content-Type": "application/x-www-form-urlencoded", - }, - "data": "foo1=$foo1&foo2=$foo2", - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.form.foo1", "session_bar1"]}, - {"eq": ["body.form.foo2", "bar2"]}, - ], - } + Step( + RunRequest("post form data") + .with_variables(**{"foo1": "bar1", "foo2": "bar2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/${get_httprunner_version()}", + "Content-Type": "application/x-www-form-urlencoded", + } + ) + .with_data("foo1=$foo1&foo2=$foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.form.foo1", "session_bar1") + .assert_equal("body.form.foo2", "bar2") ), ] diff --git a/examples/postman_echo/request_methods/request_with_testcase_reference_test.py b/examples/postman_echo/request_methods/request_with_testcase_reference_test.py index 7f87b2d6..2fa0b1c3 100644 --- a/examples/postman_echo/request_methods/request_with_testcase_reference_test.py +++ b/examples/postman_echo/request_methods/request_with_testcase_reference_test.py @@ -1,4 +1,4 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/request_with_testcase_reference.yml import os @@ -6,7 +6,7 @@ import sys sys.path.insert(0, os.getcwd()) -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase from examples.postman_echo.request_methods.request_with_functions_test import ( TestCaseRequestWithFunctions as RequestWithFunctions, @@ -14,23 +14,18 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( class TestCaseRequestWithTestcaseReference(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase: reference testcase", - "variables": {"foo1": "session_bar1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/request_with_testcase_reference_test.py", - } + config = ( + Config("request methods testcase: reference testcase") + .variables(**{"foo1": "session_bar1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "request with functions", - "variables": {"foo1": "override_bar1"}, - "testcase": RequestWithFunctions, - } + Step( + RunTestCase("request with functions") + .with_variables(**{"foo1": "override_bar1"}) + .call(RequestWithFunctions) ), ] diff --git a/examples/postman_echo/request_methods/request_with_variables_test.py b/examples/postman_echo/request_methods/request_with_variables_test.py index 6460eb90..4fe8e4d4 100644 --- a/examples/postman_echo/request_methods/request_with_variables_test.py +++ b/examples/postman_echo/request_methods/request_with_variables_test.py @@ -1,82 +1,63 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/request_with_variables.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithVariables(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase with variables", - "variables": {"foo1": "session_bar1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/request_with_variables_test.py", - } + config = ( + Config("request methods testcase with variables") + .variables(**{"foo1": "session_bar1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "variables": {"foo1": "bar1", "foo2": "session_bar2"}, - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "$foo1", "foo2": "$foo2"}, - "headers": {"User-Agent": "HttpRunner/3.0"}, - }, - "extract": {"session_foo2": "body.args.foo2"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.foo1", "session_bar1"]}, - {"eq": ["body.args.foo2", "session_bar2"]}, - ], - } + Step( + RunRequest("get with params") + .with_variables(**{"foo1": "bar1", "foo2": "session_bar2"}) + .get("/get") + .with_params(**{"foo1": "$foo1", "foo2": "$foo2"}) + .with_headers(**{"User-Agent": "HttpRunner/3.0"}) + .extract() + .with_jmespath("body.args.foo2", "session_foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args.foo1", "session_bar1") + .assert_equal("body.args.foo2", "session_bar2") ), - TStep( - **{ - "name": "post raw text", - "variables": {"foo1": "hello world", "foo3": "$session_foo2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body: $foo1-$foo3.", - }, - "validate": [ - {"eq": ["status_code", 200]}, - { - "eq": [ - "body.data", - "This is expected to be sent back as part of response body: session_bar1-session_bar2.", - ] - }, - ], - } + Step( + RunRequest("post raw text") + .with_variables(**{"foo1": "hello world", "foo3": "$session_foo2"}) + .post("/post") + .with_headers( + **{"User-Agent": "HttpRunner/3.0", "Content-Type": "text/plain"} + ) + .with_data( + "This is expected to be sent back as part of response body: $foo1-$foo3." + ) + .validate() + .assert_equal("status_code", 200) + .assert_equal( + "body.data", + "This is expected to be sent back as part of response body: session_bar1-session_bar2.", + ) ), - TStep( - **{ - "name": "post form data", - "variables": {"foo1": "bar1", "foo2": "bar2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "application/x-www-form-urlencoded", - }, - "data": "foo1=$foo1&foo2=$foo2", - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.form.foo1", "session_bar1"]}, - {"eq": ["body.form.foo2", "bar2"]}, - ], - } + Step( + RunRequest("post form data") + .with_variables(**{"foo1": "bar1", "foo2": "bar2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/3.0", + "Content-Type": "application/x-www-form-urlencoded", + } + ) + .with_data("foo1=$foo1&foo2=$foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.form.foo1", "session_bar1") + .assert_equal("body.form.foo2", "bar2") ), ] diff --git a/examples/postman_echo/request_methods/validate_with_functions.yml b/examples/postman_echo/request_methods/validate_with_functions.yml index 41aca935..4d8d8a83 100644 --- a/examples/postman_echo/request_methods/validate_with_functions.yml +++ b/examples/postman_echo/request_methods/validate_with_functions.yml @@ -25,5 +25,5 @@ teststeps: session_foo2: "body.args.foo2" validate: - eq: ["status_code", 200] - - eq: ["body.args.sum_v", 3] - - less_than: ["body.args.sum_v", "${sum_two(2, 2)}"] + - eq: ["body.args.sum_v", "3"] +# - less_than: ["body.args.sum_v", "${sum_two(2, 2)}"] TODO diff --git a/examples/postman_echo/request_methods/validate_with_functions_test.py b/examples/postman_echo/request_methods/validate_with_functions_test.py index 51640531..b203c16c 100644 --- a/examples/postman_echo/request_methods/validate_with_functions_test.py +++ b/examples/postman_echo/request_methods/validate_with_functions_test.py @@ -1,42 +1,31 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/validate_with_functions.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseValidateWithFunctions(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase: validate with functions", - "variables": {"foo1": "session_bar1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/validate_with_functions_test.py", - } + config = ( + Config("request methods testcase: validate with functions") + .variables(**{"foo1": "session_bar1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "variables": { - "foo1": "bar1", - "foo2": "session_bar2", - "sum_v": "${sum_two(1, 2)}", - }, - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}, - "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, - }, - "extract": {"session_foo2": "body.args.foo2"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.sum_v", 3]}, - {"less_than": ["body.args.sum_v", "${sum_two(2, 2)}"]}, - ], - } + Step( + RunRequest("get with params") + .with_variables( + **{"foo1": "bar1", "foo2": "session_bar2", "sum_v": "${sum_two(1, 2)}"} + ) + .get("/get") + .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}) + .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"}) + .extract() + .with_jmespath("body.args.foo2", "session_foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args.sum_v", "3") ), ] diff --git a/examples/postman_echo/request_methods/validate_with_variables_test.py b/examples/postman_echo/request_methods/validate_with_variables_test.py index 1cb75fa9..7a46d80d 100644 --- a/examples/postman_echo/request_methods/validate_with_variables_test.py +++ b/examples/postman_echo/request_methods/validate_with_variables_test.py @@ -1,82 +1,63 @@ -# NOTICE: Generated By HttpRunner. DO NOT EDIT! +# NOTICE: Generated By HttpRunner. # FROM: examples/postman_echo/request_methods/validate_with_variables.yml -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseValidateWithVariables(HttpRunner): - config = TConfig( - **{ - "name": "request methods testcase: validate with variables", - "variables": {"foo1": "session_bar1"}, - "base_url": "https://postman-echo.com", - "verify": False, - "path": "examples/postman_echo/request_methods/validate_with_variables_test.py", - } + config = ( + Config("request methods testcase: validate with variables") + .variables(**{"foo1": "session_bar1"}) + .base_url("https://postman-echo.com") + .verify(False) ) teststeps = [ - TStep( - **{ - "name": "get with params", - "variables": {"foo1": "bar1", "foo2": "session_bar2"}, - "request": { - "method": "GET", - "url": "/get", - "params": {"foo1": "$foo1", "foo2": "$foo2"}, - "headers": {"User-Agent": "HttpRunner/3.0"}, - }, - "extract": {"session_foo2": "body.args.foo2"}, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.args.foo1", "$foo1"]}, - {"eq": ["body.args.foo2", "$foo2"]}, - ], - } + Step( + RunRequest("get with params") + .with_variables(**{"foo1": "bar1", "foo2": "session_bar2"}) + .get("/get") + .with_params(**{"foo1": "$foo1", "foo2": "$foo2"}) + .with_headers(**{"User-Agent": "HttpRunner/3.0"}) + .extract() + .with_jmespath("body.args.foo2", "session_foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.args.foo1", "$foo1") + .assert_equal("body.args.foo2", "$foo2") ), - TStep( - **{ - "name": "post raw text", - "variables": {"foo1": "hello world", "foo3": "$session_foo2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "text/plain", - }, - "data": "This is expected to be sent back as part of response body: $foo1-$foo3.", - }, - "validate": [ - {"eq": ["status_code", 200]}, - { - "eq": [ - "body.data", - "This is expected to be sent back as part of response body: session_bar1-$foo3.", - ] - }, - ], - } + Step( + RunRequest("post raw text") + .with_variables(**{"foo1": "hello world", "foo3": "$session_foo2"}) + .post("/post") + .with_headers( + **{"User-Agent": "HttpRunner/3.0", "Content-Type": "text/plain"} + ) + .with_data( + "This is expected to be sent back as part of response body: $foo1-$foo3." + ) + .validate() + .assert_equal("status_code", 200) + .assert_equal( + "body.data", + "This is expected to be sent back as part of response body: session_bar1-$foo3.", + ) ), - TStep( - **{ - "name": "post form data", - "variables": {"foo1": "bar1", "foo2": "bar2"}, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "User-Agent": "HttpRunner/3.0", - "Content-Type": "application/x-www-form-urlencoded", - }, - "data": "foo1=$foo1&foo2=$foo2", - }, - "validate": [ - {"eq": ["status_code", 200]}, - {"eq": ["body.form.foo1", "$foo1"]}, - {"eq": ["body.form.foo2", "$foo2"]}, - ], - } + Step( + RunRequest("post form data") + .with_variables(**{"foo1": "bar1", "foo2": "bar2"}) + .post("/post") + .with_headers( + **{ + "User-Agent": "HttpRunner/3.0", + "Content-Type": "application/x-www-form-urlencoded", + } + ) + .with_data("foo1=$foo1&foo2=$foo2") + .validate() + .assert_equal("status_code", 200) + .assert_equal("body.form.foo1", "$foo1") + .assert_equal("body.form.foo2", "$foo2") ), ] diff --git a/httprunner/__init__.py b/httprunner/__init__.py index d6cc44a1..71d2df85 100644 --- a/httprunner/__init__.py +++ b/httprunner/__init__.py @@ -1,8 +1,9 @@ -__version__ = "3.0.6" +__version__ = "3.0.7" __description__ = "One-stop solution for HTTP(S) testing." from httprunner.runner import HttpRunner from httprunner.schema import TConfig, TStep +from httprunner.testcase import Config, Step, RunRequest, RunTestCase __all__ = [ "__version__", @@ -10,4 +11,8 @@ __all__ = [ "HttpRunner", "TConfig", "TStep", + "Config", + "Step", + "RunRequest", + "RunTestCase", ] diff --git a/httprunner/builtin/comparators.py b/httprunner/builtin/comparators.py index 975c868d..2a8ab78c 100644 --- a/httprunner/builtin/comparators.py +++ b/httprunner/builtin/comparators.py @@ -5,27 +5,27 @@ Built-in validate comparators. import re -def equals(check_value, expect_value): +def equal(check_value, expect_value): assert check_value == expect_value -def less_than(check_value, expect_value): - assert check_value < expect_value - - -def less_than_or_equals(check_value, expect_value): - assert check_value <= expect_value - - def greater_than(check_value, expect_value): assert check_value > expect_value -def greater_than_or_equals(check_value, expect_value): +def less_than(check_value, expect_value): + assert check_value < expect_value + + +def greater_or_equals(check_value, expect_value): assert check_value >= expect_value -def not_equals(check_value, expect_value): +def less_or_equals(check_value, expect_value): + assert check_value <= expect_value + + +def not_equal(check_value, expect_value): assert check_value != expect_value @@ -33,34 +33,29 @@ def string_equals(check_value, expect_value): assert str(check_value) == str(expect_value) -def length_equals(check_value, expect_value): +def length_equal(check_value, expect_value): assert isinstance(expect_value, int) - expect_len = _cast_to_int(expect_value) - assert len(check_value) == expect_len + assert len(check_value) == expect_value def length_greater_than(check_value, expect_value): - assert isinstance(expect_value, int) - expect_len = _cast_to_int(expect_value) - assert len(check_value) > expect_len + assert isinstance(expect_value, (int, float)) + assert len(check_value) > expect_value -def length_greater_than_or_equals(check_value, expect_value): - assert isinstance(expect_value, int) - expect_len = _cast_to_int(expect_value) - assert len(check_value) >= expect_len +def length_greater_or_equals(check_value, expect_value): + assert isinstance(expect_value, (int, float)) + assert len(check_value) >= expect_value def length_less_than(check_value, expect_value): - assert isinstance(expect_value, int) - expect_len = _cast_to_int(expect_value) - assert len(check_value) < expect_len + assert isinstance(expect_value, (int, float)) + assert len(check_value) < expect_value -def length_less_than_or_equals(check_value, expect_value): - assert isinstance(expect_value, int) - expect_len = _cast_to_int(expect_value) - assert len(check_value) <= expect_len +def length_less_or_equals(check_value, expect_value): + assert isinstance(expect_value, (int, float)) + assert len(check_value) <= expect_value def contains(check_value, expect_value): @@ -100,10 +95,3 @@ def startswith(check_value, expect_value): def endswith(check_value, expect_value): assert str(check_value).endswith(str(expect_value)) - - -def _cast_to_int(expect_value): - try: - return int(expect_value) - except Exception: - raise AssertionError("%r can't cast to int" % str(expect_value)) diff --git a/httprunner/cli.py b/httprunner/cli.py index c86cca75..5297074d 100644 --- a/httprunner/cli.py +++ b/httprunner/cli.py @@ -44,7 +44,7 @@ def main_run(extra_args): sys.exit(1) extra_args_new.extend(testcase_path_list) - pytest.main(extra_args_new) + sys.exit(pytest.main(extra_args_new)) def main(): diff --git a/httprunner/client.py b/httprunner/client.py index e1ade62a..e6116bb7 100644 --- a/httprunner/client.py +++ b/httprunner/client.py @@ -41,7 +41,7 @@ def get_req_resp_record(resp_obj: Response) -> ReqRespData: # record actual request info request_headers = dict(resp_obj.request.headers) - request_cookies = dict(resp_obj.request._cookies) + request_cookies = resp_obj.request._cookies.get_dict() request_body = resp_obj.request.body try: request_body = json.loads(request_body) diff --git a/httprunner/compat.py b/httprunner/compat.py index d34c0001..2d7fd593 100644 --- a/httprunner/compat.py +++ b/httprunner/compat.py @@ -265,7 +265,9 @@ def session_fixture(request): ) summary["stat"]["teststeps"]["failures"] += 1 - summary["details"].append(testcase_summary.dict()) + testcase_summary_json = testcase_summary.dict() + testcase_summary_json["records"] = testcase_summary_json.pop("step_datas") + summary["details"].append(testcase_summary_json) summary_path = "{{SUMMARY_PATH_PLACEHOLDER}}" summary_dir = os.path.dirname(summary_path) diff --git a/httprunner/ext/har2case/__init__.py b/httprunner/ext/har2case/__init__.py index 3847d7c3..ade2ac36 100644 --- a/httprunner/ext/har2case/__init__.py +++ b/httprunner/ext/har2case/__init__.py @@ -30,7 +30,14 @@ def init_har2case_parser(subparsers): "--to-yaml", dest="to_yaml", action="store_true", - help="Convert to YAML format, if not specified, convert to JSON format by default.", + help="Convert to YAML format, if not specified, convert to pytest format by default.", + ) + parser.add_argument( + "-2j", + "--to-json", + dest="to_json", + action="store_true", + help="Convert to JSON format, if not specified, convert to pytest format by default.", ) parser.add_argument( "--filter", @@ -55,7 +62,13 @@ def main_har2case(args): logger.error(f"HAR file not exists: {har_source_file}") sys.exit(1) - output_file_type = "YML" if args.to_yaml else "JSON" + if args.to_yaml: + output_file_type = "YAML" + elif args.to_yaml: + output_file_type = "JSON" + else: + output_file_type = "pytest" + HarParser(har_source_file, args.filter, args.exclude).gen_testcase(output_file_type) return 0 diff --git a/httprunner/ext/har2case/core.py b/httprunner/ext/har2case/core.py index 3130a91c..56d14464 100644 --- a/httprunner/ext/har2case/core.py +++ b/httprunner/ext/har2case/core.py @@ -7,6 +7,7 @@ import urllib.parse as urlparse from loguru import logger from httprunner.ext.har2case import utils +from httprunner.make import make_testcase, format_pytest_with_black try: from json.decoder import JSONDecodeError @@ -329,17 +330,23 @@ class HarParser(object): testcase = {"config": config, "teststeps": teststeps} return testcase - def gen_testcase(self, file_type="JSON"): + def gen_testcase(self, file_type="pytest"): logger.info(f"Start to generate testcase from {self.har_file_path}") harfile = os.path.splitext(self.har_file_path)[0] - output_testcase_file = "{}.{}".format(harfile, file_type.lower()) testcase = self._make_testcase() logger.debug("prepared testcase: {}".format(testcase)) if file_type == "JSON": + output_testcase_file = f"{harfile}.json" utils.dump_json(testcase, output_testcase_file) - else: + elif file_type == "YAML": + output_testcase_file = f"{harfile}.yml" utils.dump_yaml(testcase, output_testcase_file) + else: + # default to generate pytest file + testcase["config"]["path"] = self.har_file_path + output_testcase_file = make_testcase(testcase) + format_pytest_with_black(output_testcase_file) logger.info(f"generated testcase: {output_testcase_file}") diff --git a/httprunner/loader.py b/httprunner/loader.py index 27ea6124..4ef030e3 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -48,7 +48,6 @@ def _load_json_file(json_file: Text) -> Dict: json_content = json.load(data_file) except json.JSONDecodeError as ex: err_msg = f"JSONDecodeError:\nfile: {json_file}\nerror: {ex}" - logger.error(err_msg) raise exceptions.FileFormatError(err_msg) return json_content @@ -74,12 +73,11 @@ def load_test_file(test_file: Text) -> Dict: def load_testcase(testcase: Dict) -> TestCase: - path = testcase["config"]["path"] try: # validate with pydantic TestCase model testcase_obj = TestCase.parse_obj(testcase) except ValidationError as ex: - err_msg = f"TestCase ValidationError:\nfile: {path}\nerror: {ex}" + err_msg = f"TestCase ValidationError:\nerror: {ex}\ncontent: {testcase}" logger.error(err_msg) raise exceptions.TestCaseFormatError(err_msg) @@ -89,8 +87,8 @@ def load_testcase(testcase: Dict) -> TestCase: def load_testcase_file(testcase_file: Text) -> TestCase: """load testcase file and validate with pydantic model""" testcase_content = load_test_file(testcase_file) - testcase_content.setdefault("config", {})["path"] = testcase_file testcase_obj = load_testcase(testcase_content) + testcase_obj.config.path = testcase_file return testcase_obj @@ -195,7 +193,7 @@ def load_csv_file(csv_file: Text) -> List[Dict]: def load_folder_files(folder_path: Text, recursive: bool = True) -> List: - """ load folder path, return all files endswith yml/yaml/json in list. + """ load folder path, return all files endswith .yml/.yaml/.json/_test.py in list. Args: folder_path (str): specified folder path to load @@ -220,7 +218,7 @@ def load_folder_files(folder_path: Text, recursive: bool = True) -> List: filenames_list = [] for filename in filenames: - if not filename.endswith((".yml", ".yaml", ".json")): + if not filename.lower().endswith((".yml", ".yaml", ".json", "_test.py")): continue filenames_list.append(filename) diff --git a/httprunner/make.py b/httprunner/make.py index 749131dc..b5fe6fd6 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -16,13 +16,15 @@ from httprunner.loader import ( load_project_meta, ) from httprunner.parser import parse_data +from httprunner.response import uniform_validator """ cache converted pytest files, avoid duplicate making """ make_files_cache_set: Set = set() +pytest_files_set: Set = set() __TEMPLATE__ = jinja2.Template( - """# NOTICE: Generated By HttpRunner. DO NOT EDIT! + """# NOTICE: Generated By HttpRunner. # FROM: {{ testcase_path }} {% if imports_list %} import os @@ -30,17 +32,17 @@ import sys sys.path.insert(0, os.getcwd()) {% endif %} -from httprunner import HttpRunner, TConfig, TStep +from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase {% for import_str in imports_list %} {{ import_str }} {% endfor %} class {{ class_name }}(HttpRunner): - config = TConfig(**{{ config }}) + config = {{ config_chain_style }} teststeps = [ - {% for teststep in teststeps %} - TStep(**{{ teststep }}), + {% for step_chain_style in teststeps_chain_style %} + {{ step_chain_style }}, {% endfor %} ] @@ -96,7 +98,7 @@ def __ensure_testcase_module(path: Text) -> NoReturn: return with open(init_file, "w", encoding="utf-8") as f: - f.write("# NOTICE: Generated By HttpRunner. DO NOT EDIT!") + f.write("# NOTICE: Generated By HttpRunner. DO NOT EDIT!\n") def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]: @@ -109,7 +111,7 @@ def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]: raw_file_name, file_suffix = os.path.splitext(os.path.basename(testcase_path)) file_suffix = file_suffix.lower() - if file_suffix not in [".json", ".yml", ".yaml"]: + if file_suffix not in [".json", ".yml", ".yaml", ".har"]: raise exceptions.ParamsError( "testcase file should have .yaml/.yml/.json suffix" ) @@ -124,7 +126,7 @@ def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]: return testcase_python_path, name_in_title_case -def __format_pytest_with_black(python_paths: List[Text]) -> NoReturn: +def format_pytest_with_black(*python_paths: Text) -> NoReturn: logger.info("format pytest cases with black ...") try: subprocess.run(["black", *python_paths]) @@ -132,7 +134,112 @@ def __format_pytest_with_black(python_paths: List[Text]) -> NoReturn: logger.error(ex) -def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn: +def make_config_chain_style(config: Dict) -> Text: + config_chain_style = f'Config("{config["name"]}")' + + if config["variables"]: + variables = config["variables"] + config_chain_style += f".variables(**{variables})" + + if "base_url" in config: + config_chain_style += f'.base_url("{config["base_url"]}")' + + if "verify" in config: + config_chain_style += f'.verify({config["verify"]})' + + return config_chain_style + + +def make_request_chain_style(request: Dict) -> Text: + method = request["method"].lower() + url = request["url"] + request_chain_style = f'.{method}("{url}")' + + if "params" in request: + params = request["params"] + request_chain_style += f".with_params(**{params})" + + if "headers" in request: + headers = request["headers"] + request_chain_style += f".with_headers(**{headers})" + + if "cookies" in request: + cookies = request["cookies"] + request_chain_style += f".with_cookies(**{cookies})" + + if "data" in request: + data = request["data"] + if isinstance(data, Text): + data = f'"{data}"' + request_chain_style += f".with_data({data})" + + if "timeout" in request: + timeout = request["timeout"] + request_chain_style += f".set_timeout({timeout})" + + if "verify" in request: + verify = request["verify"] + request_chain_style += f".set_verify({verify})" + + if "allow_redirects" in request: + allow_redirects = request["allow_redirects"] + request_chain_style += f".set_allow_redirects({allow_redirects})" + + if "upload" in request: + upload = request["upload"] + request_chain_style += f".upload(**{upload})" + + return request_chain_style + + +def make_teststep_chain_style(teststep: Dict) -> Text: + if teststep.get("request"): + step_info = f'RunRequest("{teststep["name"]}")' + elif teststep.get("testcase"): + step_info = f'RunTestCase("{teststep["name"]}")' + else: + raise exceptions.TestCaseFormatError + + if "variables" in teststep: + variables = teststep["variables"] + step_info += f".with_variables(**{variables})" + + if teststep.get("request"): + step_info += make_request_chain_style(teststep["request"]) + elif teststep.get("testcase"): + testcase = teststep["testcase"] + call_ref_testcase = f".call({testcase})" + step_info += call_ref_testcase + + if "extract" in teststep: + step_info += ".extract()" + + for extract_name, extract_path in teststep["extract"].items(): + step_info += f'.with_jmespath("{extract_path}", "{extract_name}")' + + if "validate" in teststep: + step_info += ".validate()" + + for v in teststep["validate"]: + validator = uniform_validator(v) + assert_method = validator["assert"] + check = validator["check"] + if '"' in check: + # e.g. body."user-agent" => 'body."user-agent"' + check = f"'{check}'" + else: + check = f'"{check}"' + expect = validator["expect"] + if isinstance(expect, Text): + expect = f'"{expect}"' + step_info += f".assert_{assert_method}({check}, {expect})" + + return f"Step({step_info})" + + +def make_testcase( + testcase: Dict, dir_path: Text = None, ref_flag: bool = False, +) -> Text: """convert valid testcase dict to pytest file path""" # ensure compatibility with testcase format v2 testcase = ensure_testcase_v3(testcase) @@ -151,7 +258,7 @@ def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn: global make_files_cache_set if testcase_python_path in make_files_cache_set: - return + return testcase_python_path config = testcase["config"] config["path"] = __ensure_cwd_relative(testcase_python_path) @@ -174,13 +281,13 @@ def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn: # make ref testcase pytest file ref_testcase_path = __ensure_absolute(teststep["testcase"]) - __make(ref_testcase_path) + __make(ref_testcase_path, ref_flag=True) # prepare ref testcase class name ref_testcase_python_path, ref_testcase_cls_name = convert_testcase_path( ref_testcase_path ) - teststep["testcase"] = f"CLS_LB({ref_testcase_cls_name})CLS_RB" + teststep["testcase"] = ref_testcase_cls_name # prepare import ref testcase ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1 :] @@ -193,12 +300,13 @@ def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn: data = { "testcase_path": __ensure_cwd_relative(testcase_path), "class_name": f"TestCase{testcase_cls_name}", - "config": config, - "teststeps": teststeps, "imports_list": imports_list, + "config_chain_style": make_config_chain_style(config), + "teststeps_chain_style": [ + make_teststep_chain_style(step) for step in teststeps + ], } content = __TEMPLATE__.render(data) - content = content.replace("'CLS_LB(", "").replace(")CLS_RB'", "") with open(testcase_python_path, "w", encoding="utf-8") as f: f.write(content) @@ -206,10 +314,14 @@ def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn: __ensure_testcase_module(testcase_python_path) logger.info(f"generated testcase: {testcase_python_path}") - make_files_cache_set.add(__ensure_cwd_relative(testcase_python_path)) + + if not ref_flag: + make_files_cache_set.add(__ensure_cwd_relative(testcase_python_path)) + + return testcase_python_path -def __make_testsuite(testsuite: Dict) -> NoReturn: +def make_testsuite(testsuite: Dict) -> NoReturn: """convert valid testsuite dict to pytest folder with testcases""" # validate testsuite format load_testsuite(testsuite) @@ -254,15 +366,16 @@ def __make_testsuite(testsuite: Dict) -> NoReturn: testcase_dict["config"]["variables"].update(testsuite_variables) # make testcase - __make_testcase(testcase_dict, testsuite_dir) + make_testcase(testcase_dict, testsuite_dir) -def __make(tests_path: Text) -> NoReturn: +def __make(tests_path: Text, ref_flag: bool = False) -> NoReturn: """ make testcase(s) with testcase/testsuite/folder absolute path generated pytest file path will be cached in make_files_cache_set Args: tests_path: should be in absolute path + ref_flag: flag if referenced test path """ test_files = [] @@ -275,6 +388,10 @@ def __make(tests_path: Text) -> NoReturn: raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}") for test_file in test_files: + if test_file.lower().endswith("_test.py"): + pytest_files_set.add(test_file) + continue + try: test_content = load_test_file(test_file) except (exceptions.FileNotFound, exceptions.FileFormatError) as ex: @@ -290,34 +407,36 @@ def __make(tests_path: Text) -> NoReturn: # testcase if "teststeps" in test_content: try: - __make_testcase(test_content) + make_testcase(test_content, ref_flag=ref_flag) except exceptions.TestCaseFormatError: continue # testsuite elif "testcases" in test_content: try: - __make_testsuite(test_content) + make_testsuite(test_content) except exceptions.TestSuiteFormatError: continue # invalid format else: - raise exceptions.FileFormatError( - f"test file is neither testcase nor testsuite: {test_file}" - ) + logger.warning(f"skip invalid testcase/testsuite file: {test_file}") def main_make(tests_paths: List[Text]) -> List[Text]: + if not tests_paths: + return [] + for tests_path in tests_paths: if not os.path.isabs(tests_path): tests_path = os.path.join(os.getcwd(), tests_path) __make(tests_path) - testcase_path_list = list(make_files_cache_set) - __format_pytest_with_black(testcase_path_list) - return testcase_path_list + pytest_files_set.update(make_files_cache_set) + pytest_files_list = list(pytest_files_set) + format_pytest_with_black(*pytest_files_list) + return pytest_files_list def init_make_parser(subparsers): diff --git a/httprunner/response.py b/httprunner/response.py index 8c698542..9a62c708 100644 --- a/httprunner/response.py +++ b/httprunner/response.py @@ -12,45 +12,39 @@ from httprunner.schema import VariablesMapping, Validators, FunctionsMapping def get_uniform_comparator(comparator: Text): """ convert comparator alias to uniform name """ - if comparator in ["eq", "equals", "==", "is"]: - return "equals" + if comparator in ["eq", "equals", "equal"]: + return "equal" elif comparator in ["lt", "less_than"]: return "less_than" - elif comparator in ["le", "less_than_or_equals"]: - return "less_than_or_equals" + elif comparator in ["le", "less_or_equals"]: + return "less_or_equals" elif comparator in ["gt", "greater_than"]: return "greater_than" - elif comparator in ["ge", "greater_than_or_equals"]: - return "greater_than_or_equals" - elif comparator in ["ne", "not_equals"]: - return "not_equals" + elif comparator in ["ge", "greater_or_equals"]: + return "greater_or_equals" + elif comparator in ["ne", "not_equal"]: + return "not_equal" elif comparator in ["str_eq", "string_equals"]: return "string_equals" - elif comparator in ["len_eq", "length_equals", "count_eq"]: - return "length_equals" + elif comparator in ["len_eq", "length_equal"]: + return "length_equal" elif comparator in [ "len_gt", - "count_gt", "length_greater_than", - "count_greater_than", ]: return "length_greater_than" elif comparator in [ "len_ge", - "count_ge", - "length_greater_than_or_equals", - "count_greater_than_or_equals", + "length_greater_or_equals", ]: - return "length_greater_than_or_equals" - elif comparator in ["len_lt", "count_lt", "length_less_than", "count_less_than"]: + return "length_greater_or_equals" + elif comparator in ["len_lt", "length_less_than"]: return "length_less_than" elif comparator in [ "len_le", - "count_le", - "length_less_than_or_equals", - "count_less_than_or_equals", + "length_less_or_equals", ]: - return "length_less_than_or_equals" + return "length_less_or_equals" else: return comparator @@ -62,8 +56,8 @@ def uniform_validator(validator): validator (dict): validator maybe in two formats: format1: this is kept for compatibility with the previous versions. - {"check": "status_code", "assert": "eq", "expect": 201} - {"check": "$resp_body_success", "assert": "eq", "expect": True} + {"check": "status_code", "comparator": "eq", "expect": 201} + {"check": "$resp_body_success", "comparator": "eq", "expect": True} format2: recommended new version, {assert: [check_item, expected_value]} {'eq': ['status_code', 201]} {'eq': ['$resp_body_success', True]} @@ -169,11 +163,10 @@ class ResponseObject(object): check_value = parse_data( check_item, variables_mapping, functions_mapping ) + check_value = parse_string_value(check_value) else: check_value = jmespath.search(check_item, self.resp_obj_meta) - check_value = parse_string_value(check_value) - # comparator assert_method = u_validator["assert"] assert_func = get_mapping_function(assert_method, functions_mapping) diff --git a/httprunner/runner.py b/httprunner/runner.py index d236d471..9b94cf5e 100644 --- a/httprunner/runner.py +++ b/httprunner/runner.py @@ -2,7 +2,7 @@ import os import time import uuid from datetime import datetime -from typing import List, Dict, Text +from typing import List, Dict, Text, NoReturn try: import allure @@ -20,6 +20,7 @@ from httprunner.ext.uploader import prepare_upload_step from httprunner.loader import load_project_meta, load_testcase_file from httprunner.parser import build_url, parse_data, parse_variables_mapping from httprunner.response import ResponseObject +from httprunner.testcase import Config, Step from httprunner.schema import ( TConfig, TStep, @@ -34,10 +35,12 @@ from httprunner.schema import ( class HttpRunner(object): - config: TConfig - teststeps: List[TStep] + config: Config + teststeps: List[Step] success: bool = True # indicate testcase execution result + __config: TConfig + __teststeps: List[TStep] __project_meta: ProjectMeta = None __case_id: Text = "" __step_datas: List[StepData] = None @@ -49,6 +52,19 @@ class HttpRunner(object): # log __log_path: Text = "" + def __init_tests__(self) -> NoReturn: + self.__config = self.config.perform() + self.__teststeps = [] + for step in self.teststeps: + self.__teststeps.append(step.perform()) + + @property + def raw_testcase(self) -> TestCase: + if not hasattr(self, "__config"): + self.__init_tests__() + + return TestCase(config=self.__config, teststeps=self.__teststeps) + def with_project_meta(self, project_meta: ProjectMeta) -> "HttpRunner": self.__project_meta = project_meta return self @@ -65,7 +81,7 @@ class HttpRunner(object): self.__session_variables = variables return self - def __run_step_request(self, step: TStep): + def __run_step_request(self, step: TStep) -> StepData: """run teststep: request""" step_data = StepData(name=step.name) @@ -84,7 +100,7 @@ class HttpRunner(object): # prepare arguments method = parsed_request_dict.pop("method") url_path = parsed_request_dict.pop("url") - url = build_url(self.config.base_url, url_path) + url = build_url(self.__config.base_url, url_path) parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {}) # request @@ -142,7 +158,7 @@ class HttpRunner(object): return step_data - def __run_step_testcase(self, step): + def __run_step_testcase(self, step: TStep) -> StepData: """run teststep: referenced testcase""" step_data = StepData(name=step.name) step_variables = step.variables @@ -183,7 +199,7 @@ class HttpRunner(object): return step_data - def __run_step(self, step: TStep): + def __run_step(self, step: TStep) -> Dict: """run teststep, teststep maybe a request or referenced testcase""" logger.info(f"run step begin: {step.name} >>>>>>") @@ -200,7 +216,7 @@ class HttpRunner(object): logger.info(f"run step end: {step.name} <<<<<<\n") return step_data.export - def __parse_config(self, config: TConfig): + def __parse_config(self, config: TConfig) -> NoReturn: config.variables.update(self.__session_variables) config.variables = parse_variables_mapping( config.variables, self.__project_meta.functions @@ -212,7 +228,7 @@ class HttpRunner(object): config.base_url, config.variables, self.__project_meta.functions ) - def run_testcase(self, testcase: TestCase): + def run_testcase(self, testcase: TestCase) -> "HttpRunner": """run specified testcase Examples: @@ -220,21 +236,23 @@ class HttpRunner(object): >>> HttpRunner().with_project_meta(project_meta).run_testcase(testcase_obj) """ - self.config = testcase.config - self.teststeps = testcase.teststeps + self.__config = testcase.config + self.__teststeps = testcase.teststeps # prepare - self.__project_meta = self.__project_meta or load_project_meta(self.config.path) - self.__parse_config(self.config) + self.__project_meta = self.__project_meta or load_project_meta( + self.__config.path + ) + self.__parse_config(self.__config) self.__start_at = time.time() self.__step_datas: List[StepData] = [] self.__session = self.__session or HttpSession() self.__session_variables = {} # run teststeps - for step in self.teststeps: + for step in self.__teststeps: # update with config variables - step.variables.update(self.config.variables) + step.variables.update(self.__config.variables) # update with session variables extracted from pre step step.variables.update(self.__session_variables) # parse variables @@ -267,7 +285,8 @@ class HttpRunner(object): >>> TestCaseRequestWithFunctions().run() """ - testcase_obj = TestCase(config=self.config, teststeps=self.teststeps) + self.__init_tests__() + testcase_obj = TestCase(config=self.__config, teststeps=self.__teststeps) return self.run_testcase(testcase_obj) def get_step_datas(self) -> List[StepData]: @@ -275,7 +294,7 @@ class HttpRunner(object): def get_export_variables(self) -> Dict: export_vars_mapping = {} - for var_name in self.config.export: + for var_name in self.__config.export: if var_name not in self.__session_variables: raise ParamsError( f"failed to export variable {var_name} from session variables {self.__session_variables}" @@ -290,7 +309,7 @@ class HttpRunner(object): start_at_timestamp = self.__start_at start_at_iso_format = datetime.utcfromtimestamp(start_at_timestamp).isoformat() return TestCaseSummary( - name=self.config.name, + name=self.__config.name, success=self.success, case_id=self.__case_id, time=TestCaseTime( @@ -299,15 +318,18 @@ class HttpRunner(object): duration=self.__duration, ), in_out=TestCaseInOut( - vars=self.config.variables, export=self.get_export_variables() + vars=self.__config.variables, export=self.get_export_variables() ), log=self.__log_path, step_datas=self.__step_datas, ) - def test_start(self): + def test_start(self) -> "HttpRunner": """main entrance, discovered by pytest""" - self.__project_meta = self.__project_meta or load_project_meta(self.config.path) + self.__init_tests__() + self.__project_meta = self.__project_meta or load_project_meta( + self.__config.path + ) self.__case_id = self.__case_id or str(uuid.uuid4()) self.__log_path = self.__log_path or os.path.join( self.__project_meta.PWD, "logs", f"{self.__case_id}.run.log" @@ -315,24 +337,24 @@ class HttpRunner(object): log_handler = logger.add(self.__log_path, level="DEBUG") # parse config name - variables = self.config.variables + variables = self.__config.variables variables.update(self.__session_variables) - self.config.name = parse_data( - self.config.name, variables, self.__project_meta.functions + self.__config.name = parse_data( + self.__config.name, variables, self.__project_meta.functions ) if USE_ALLURE: # update allure report meta - allure.dynamic.title(self.config.name) + allure.dynamic.title(self.__config.name) allure.dynamic.description(f"TestCase ID: {self.__case_id}") logger.info( - f"Start to run testcase: {self.config.name}, TestCase ID: {self.__case_id}" + f"Start to run testcase: {self.__config.name}, TestCase ID: {self.__case_id}" ) try: return self.run_testcase( - TestCase(config=self.config, teststeps=self.teststeps) + TestCase(config=self.__config, teststeps=self.__teststeps) ) finally: logger.remove(log_handler) diff --git a/httprunner/scaffold.py b/httprunner/scaffold.py index 9fe48471..bf48893f 100644 --- a/httprunner/scaffold.py +++ b/httprunner/scaffold.py @@ -66,7 +66,7 @@ teststeps: validate: - eq: ["status_code", 200] - eq: ["body.args.foo1", "session_bar1"] - - eq: ["body.args.sum_v", 3] + - eq: ["body.args.sum_v", "3"] - eq: ["body.args.foo2", "session_bar2"] - name: post raw text diff --git a/httprunner/schema.py b/httprunner/schema.py index 986f6cb2..59ff17f6 100644 --- a/httprunner/schema.py +++ b/httprunner/schema.py @@ -29,8 +29,6 @@ class MethodEnum(Text, Enum): HEAD = "HEAD" OPTIONS = "OPTIONS" PATCH = "PATCH" - CONNECT = "CONNECT" - TRACE = "TRACE" class TConfig(BaseModel): @@ -45,17 +43,17 @@ class TConfig(BaseModel): path: Text = None -class Request(BaseModel): +class TRequest(BaseModel): """requests.Request model""" - method: MethodEnum = MethodEnum.GET + method: MethodEnum url: Url params: Dict[Text, Text] = {} headers: Headers = {} - req_json: Dict = Field({}, alias="json") + req_json: Union[Dict, List] = Field({}, alias="json") data: Union[Text, Dict[Text, Any]] = "" cookies: Cookies = {} - timeout: int = 120 + timeout: float = 120 allow_redirects: bool = True verify: Verify = False upload: Dict = {} # used for upload files @@ -63,8 +61,8 @@ class Request(BaseModel): class TStep(BaseModel): name: Name - request: Request = None - testcase: Union[Text, Callable] = "" + request: Union[TRequest, None] = None + testcase: Union[Text, Callable, None] = None variables: VariablesMapping = {} setup_hooks: Hook = [] teardown_hooks: Hook = [] diff --git a/httprunner/testcase.py b/httprunner/testcase.py new file mode 100644 index 00000000..bcbfb07d --- /dev/null +++ b/httprunner/testcase.py @@ -0,0 +1,318 @@ +import inspect +from typing import Text, Any, Union, Callable + +from httprunner.schema import ( + TConfig, + TStep, + TRequest, + MethodEnum, + TestCase, +) + + +class Config(object): + def __init__(self, name: Text): + self.__name = name + self.__variables = {} + self.__base_url = "" + self.__verify = False + + caller_frame = inspect.stack()[1] + self.__path = caller_frame.filename + + @property + def name(self): + return self.__name + + @property + def path(self): + return self.__path + + def variables(self, **variables) -> "Config": + self.__variables.update(variables) + return self + + def base_url(self, base_url: Text) -> "Config": + self.__base_url = base_url + return self + + def verify(self, verify: bool) -> "Config": + self.__verify = verify + return self + + def perform(self) -> TConfig: + return TConfig( + name=self.__name, + base_url=self.__base_url, + verify=self.__verify, + variables=self.__variables, + path=self.__path, + ) + + +class StepValidation(object): + def __init__(self, step: TStep): + self.__t_step = step + + def assert_equal(self, jmes_path: Text, expected_value: Any) -> "StepValidation": + self.__t_step.validators.append({"equal": [jmes_path, expected_value]}) + return self + + def assert_not_equal( + self, jmes_path: Text, expected_value: Any + ) -> "StepValidation": + self.__t_step.validators.append({"not_equal": [jmes_path, expected_value]}) + return self + + def assert_greater_than( + self, jmes_path: Text, expected_value: Union[int, float] + ) -> "StepValidation": + self.__t_step.validators.append({"greater_than": [jmes_path, expected_value]}) + return self + + def assert_less_than( + self, jmes_path: Text, expected_value: Union[int, float] + ) -> "StepValidation": + self.__t_step.validators.append({"less_than": [jmes_path, expected_value]}) + return self + + def assert_greater_or_equals( + self, jmes_path: Text, expected_value: Union[int, float] + ) -> "StepValidation": + self.__t_step.validators.append( + {"greater_or_equals": [jmes_path, expected_value]} + ) + return self + + def assert_less_or_equals( + self, jmes_path: Text, expected_value: Union[int, float] + ) -> "StepValidation": + self.__t_step.validators.append({"less_or_equals": [jmes_path, expected_value]}) + return self + + def assert_length_equal( + self, jmes_path: Text, expected_value: int + ) -> "StepValidation": + self.__t_step.validators.append({"length_equal": [jmes_path, expected_value]}) + return self + + def assert_length_greater_than( + self, jmes_path: Text, expected_value: int + ) -> "StepValidation": + self.__t_step.validators.append( + {"length_greater_than": [jmes_path, expected_value]} + ) + return self + + def assert_length_less_than( + self, jmes_path: Text, expected_value: int + ) -> "StepValidation": + self.__t_step.validators.append( + {"length_less_than": [jmes_path, expected_value]} + ) + return self + + def assert_length_greater_or_equals( + self, jmes_path: Text, expected_value: int + ) -> "StepValidation": + self.__t_step.validators.append( + {"length_greater_or_equals": [jmes_path, expected_value]} + ) + return self + + def assert_length_less_or_equals( + self, jmes_path: Text, expected_value: int + ) -> "StepValidation": + self.__t_step.validators.append( + {"length_less_or_equals": [jmes_path, expected_value]} + ) + return self + + def assert_string_equals( + self, jmes_path: Text, expected_value: int + ) -> "StepValidation": + self.__t_step.validators.append({"string_equals": [jmes_path, expected_value]}) + return self + + def assert_startswith( + self, jmes_path: Text, expected_value: Text + ) -> "StepValidation": + self.__t_step.validators.append({"startswith": [jmes_path, expected_value]}) + return self + + def assert_endswith( + self, jmes_path: Text, expected_value: Text + ) -> "StepValidation": + self.__t_step.validators.append({"endswith": [jmes_path, expected_value]}) + return self + + def assert_regex_match( + self, jmes_path: Text, expected_value: Text + ) -> "StepValidation": + self.__t_step.validators.append({"regex_match": [jmes_path, expected_value]}) + return self + + def assert_contains(self, jmes_path: Text, expected_value: Any) -> "StepValidation": + self.__t_step.validators.append({"contains": [jmes_path, expected_value]}) + return self + + def assert_contained_by( + self, jmes_path: Text, expected_value: Any + ) -> "StepValidation": + self.__t_step.validators.append({"contained_by": [jmes_path, expected_value]}) + return self + + def assert_type_match( + self, jmes_path: Text, expected_value: Text + ) -> "StepValidation": + self.__t_step.validators.append({"type_match": [jmes_path, expected_value]}) + return self + + def perform(self) -> TStep: + return self.__t_step + + +class StepExtraction(object): + def __init__(self, step: TStep): + self.__t_step = step + + def with_jmespath(self, jmes_path: Text, var_name: Text) -> "StepExtraction": + self.__t_step.extract[var_name] = jmes_path + return self + + # def with_regex(self): + # # TODO: extract response html with regex + # pass + # + # def with_jsonpath(self): + # # TODO: extract response json with jsonpath + # pass + + def validate(self) -> StepValidation: + return StepValidation(self.__t_step) + + def perform(self) -> TStep: + return self.__t_step + + +class RequestWithOptionalArgs(object): + def __init__(self, step: TStep): + self.__t_step = step + + def with_params(self, **params) -> "RequestWithOptionalArgs": + self.__t_step.request.params.update(params) + return self + + def with_headers(self, **headers) -> "RequestWithOptionalArgs": + self.__t_step.request.headers.update(headers) + return self + + def with_cookies(self, **cookies) -> "RequestWithOptionalArgs": + self.__t_step.request.cookies.update(cookies) + return self + + def with_data(self, data) -> "RequestWithOptionalArgs": + self.__t_step.request.data = data + return self + + def set_timeout(self, timeout: float) -> "RequestWithOptionalArgs": + self.__t_step.request.timeout = timeout + return self + + def set_verify(self, verify: bool) -> "RequestWithOptionalArgs": + self.__t_step.request.verify = verify + return self + + def set_allow_redirects(self, allow_redirects: bool) -> "RequestWithOptionalArgs": + self.__t_step.request.allow_redirects = allow_redirects + return self + + def upload(self, **file_info) -> "RequestWithOptionalArgs": + self.__t_step.request.upload.update(file_info) + return self + + # def hooks(self): + # pass + + def extract(self) -> StepExtraction: + return StepExtraction(self.__t_step) + + def validate(self) -> StepValidation: + return StepValidation(self.__t_step) + + def perform(self) -> TStep: + return self.__t_step + + +class RunRequest(object): + def __init__(self, name: Text): + self.__t_step = TStep(name=name) + + def with_variables(self, **variables) -> "RunRequest": + self.__t_step.variables.update(variables) + return self + + def get(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.GET, url=url) + return RequestWithOptionalArgs(self.__t_step) + + def post(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.POST, url=url) + return RequestWithOptionalArgs(self.__t_step) + + def put(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.PUT, url=url) + return RequestWithOptionalArgs(self.__t_step) + + def head(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.HEAD, url=url) + return RequestWithOptionalArgs(self.__t_step) + + def delete(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.DELETE, url=url) + return RequestWithOptionalArgs(self.__t_step) + + def options(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.OPTIONS, url=url) + return RequestWithOptionalArgs(self.__t_step) + + def patch(self, url: Text) -> RequestWithOptionalArgs: + self.__t_step.request = TRequest(method=MethodEnum.PATCH, url=url) + return RequestWithOptionalArgs(self.__t_step) + + +class RunTestCase(object): + def __init__(self, name: Text): + self.__t_step = TStep(name=name) + + def with_variables(self, **variables) -> "RunTestCase": + self.__t_step.variables.update(variables) + return self + + def call(self, testcase: Callable): + self.__t_step.testcase = testcase + return self + + def perform(self) -> TStep: + return self.__t_step + + +class Step(object): + def __init__( + self, + step: Union[ + StepValidation, StepExtraction, RequestWithOptionalArgs, RunTestCase + ], + ): + self.__t_step = step.perform() + + @property + def request(self) -> TRequest: + return self.__t_step.request + + @property + def testcase(self) -> TestCase: + return self.__t_step.testcase + + def perform(self) -> TStep: + return self.__t_step diff --git a/pyproject.toml b/pyproject.toml index ec8c3459..083c1725 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "httprunner" -version = "3.0.6" +version = "3.0.7" description = "One-stop solution for HTTP(S) testing." license = "Apache-2.0" readme = "README.md" diff --git a/tests/ext/har2case/core_test.py b/tests/ext/har2case/core_test.py index 329dde57..21e818ad 100644 --- a/tests/ext/har2case/core_test.py +++ b/tests/ext/har2case/core_test.py @@ -34,7 +34,7 @@ class TestHar(TestHar2CaseUtils): self.assertIn("validate", teststeps[0]) def test_gen_testcase_yaml(self): - yaml_file = os.path.join(os.path.dirname(__file__), "data", "demo.yaml") + yaml_file = os.path.join(os.path.dirname(__file__), "data", "demo.yml") self.har_parser.gen_testcase(file_type="YAML") self.assertTrue(os.path.isfile(yaml_file)) diff --git a/tests/make_test.py b/tests/make_test.py index cabb27ed..8eec7ca6 100644 --- a/tests/make_test.py +++ b/tests/make_test.py @@ -1,9 +1,16 @@ import unittest -from httprunner.make import main_make, convert_testcase_path, make_files_cache_set +from httprunner.make import ( + main_make, + convert_testcase_path, + make_files_cache_set, + make_config_chain_style, + make_teststep_chain_style, + pytest_files_set, +) -class TestLoader(unittest.TestCase): +class TestMake(unittest.TestCase): def test_make_testcase(self): path = ["examples/postman_echo/request_methods/request_with_variables.yml"] testcase_python_list = main_make(path) @@ -17,8 +24,9 @@ class TestLoader(unittest.TestCase): "examples/postman_echo/request_methods/request_with_testcase_reference.yml" ] make_files_cache_set.clear() + pytest_files_set.clear() testcase_python_list = main_make(path) - self.assertEqual(len(testcase_python_list), 2) + self.assertEqual(len(testcase_python_list), 1) self.assertIn( "examples/postman_echo/request_methods/request_with_testcase_reference_test.py", testcase_python_list, @@ -37,7 +45,7 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( content, ) self.assertIn( - '"testcase": RequestWithFunctions,', content, + ".call(RequestWithFunctions)", content, ) def test_make_testcase_folder(self): @@ -85,8 +93,9 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( def test_make_testsuite(self): path = ["examples/postman_echo/request_methods/demo_testsuite.yml"] make_files_cache_set.clear() + pytest_files_set.clear() testcase_python_list = main_make(path) - self.assertEqual(len(testcase_python_list), 3) + self.assertEqual(len(testcase_python_list), 2) self.assertIn( "examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py", testcase_python_list, @@ -95,7 +104,42 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( "examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py", testcase_python_list, ) - self.assertIn( - "examples/postman_echo/request_methods/request_with_functions_test.py", - testcase_python_list, + + def test_make_config_chain_style(self): + config = { + "name": "request methods testcase: validate with functions", + "variables": {"foo1": "bar1", "foo2": 22}, + "base_url": "https://postman-echo.com", + "verify": False, + "path": "examples/postman_echo/request_methods/validate_with_functions_test.py", + } + self.assertEqual( + make_config_chain_style(config), + """Config("request methods testcase: validate with functions").variables(**{'foo1': 'bar1', 'foo2': 22}).base_url("https://postman-echo.com").verify(False)""", + ) + + def test_make_teststep_chain_style(self): + step = { + "name": "get with params", + "variables": {"foo1": "bar1", "foo2": 123, "sum_v": "${sum_two(1, 2)}",}, + "request": { + "method": "GET", + "url": "/get", + "params": {"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"}, + "headers": {"User-Agent": "HttpRunner/${get_httprunner_version()}"}, + }, + "testcase": "CLS_LB(TestCaseDemo)CLS_RB", + "extract": { + "session_foo1": "body.args.foo1", + "session_foo2": "body.args.foo2", + }, + "validate": [ + {"eq": ["status_code", 200]}, + {"eq": ["body.args.sum_v", "3"]}, + ], + } + teststep_chain_style = make_teststep_chain_style(step) + self.assertEqual( + teststep_chain_style, + """Step(RunRequest("get with params").with_variables(**{'foo1': 'bar1', 'foo2': 123, 'sum_v': '${sum_two(1, 2)}'}).get("/get").with_params(**{'foo1': '$foo1', 'foo2': '$foo2', 'sum_v': '$sum_v'}).with_headers(**{'User-Agent': 'HttpRunner/${get_httprunner_version()}'}).extract().with_jmespath("body.args.foo1", "session_foo1").with_jmespath("body.args.foo2", "session_foo2").validate().assert_equal("status_code", 200).assert_equal("body.args.sum_v", "3"))""", ) diff --git a/tests/utils_test.py b/tests/utils_test.py index 6558325c..cfb86e85 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -12,33 +12,32 @@ class TestUtils(unittest.TestCase): self.assertIn("abc", os.environ) self.assertEqual(os.environ["abc"], "123") - def current_validators(self): + def test_validators(self): from httprunner.builtin import comparators functions_mapping = loader.load_module_functions(comparators) - functions_mapping["equals"](None, None) - functions_mapping["equals"](1, 1) - functions_mapping["equals"]("abc", "abc") + functions_mapping["equal"](None, None) + functions_mapping["equal"](1, 1) + functions_mapping["equal"]("abc", "abc") with self.assertRaises(AssertionError): - functions_mapping["equals"]("123", 123) + functions_mapping["equal"]("123", 123) functions_mapping["less_than"](1, 2) - functions_mapping["less_than_or_equals"](2, 2) + functions_mapping["less_or_equals"](2, 2) functions_mapping["greater_than"](2, 1) - functions_mapping["greater_than_or_equals"](2, 2) + functions_mapping["greater_or_equals"](2, 2) - functions_mapping["not_equals"](123, "123") + functions_mapping["not_equal"](123, "123") - functions_mapping["length_equals"]("123", 3) - # Because the Numbers in a CSV file are by default treated as strings, - # you need to convert them to Numbers, and we'll test that out here. - functions_mapping["length_equals"]("123", "3") + functions_mapping["length_equal"]("123", 3) with self.assertRaises(AssertionError): - functions_mapping["length_equals"]("123", "abc") + functions_mapping["length_equal"]("123", "3") + with self.assertRaises(AssertionError): + functions_mapping["length_equal"]("123", "abc") functions_mapping["length_greater_than"]("123", 2) - functions_mapping["length_greater_than_or_equals"]("123", 3) + functions_mapping["length_greater_or_equals"]("123", 3) functions_mapping["contains"]("123abc456", "3ab") functions_mapping["contains"](["1", "2"], "1")