mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
Merge pull request #918 from httprunner/v3
## 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
This commit is contained in:
6
.github/workflows/integration_test.yml
vendored
6
.github/workflows/integration_test.yml
vendored
@@ -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/
|
||||
|
||||
@@ -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**
|
||||
|
||||
1
examples/httpbin/__init__.py
Normal file
1
examples/httpbin/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# NOTICE: Generated By HttpRunner. DO NOT EDIT!
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
34
examples/postman_echo/cookie_manipulation/hardcode.yml
Normal file
34
examples/postman_echo/cookie_manipulation/hardcode.yml
Normal file
@@ -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"]
|
||||
54
examples/postman_echo/cookie_manipulation/hardcode_test.py
Normal file
54
examples/postman_echo/cookie_manipulation/hardcode_test.py
Normal file
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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__}")
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# NOTICE: Generated By HttpRunner. DO NOT EDIT!
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
318
httprunner/testcase.py
Normal file
318
httprunner/testcase.py
Normal file
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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"))""",
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user