api-test-toolkit 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- api_test_kit/__init__.py +18 -0
- api_test_kit/assertions.py +128 -0
- api_test_kit/cli.py +45 -0
- api_test_kit/client.py +208 -0
- api_test_kit/config.py +82 -0
- api_test_kit/e2e/__init__.py +15 -0
- api_test_kit/e2e/context.py +63 -0
- api_test_kit/e2e/helpers.py +26 -0
- api_test_kit/e2e/scenario.py +113 -0
- api_test_kit/e2e/step.py +99 -0
- api_test_kit/endpoints/__init__.py +44 -0
- api_test_kit/endpoints/_base.py +44 -0
- api_test_kit/logger.py +25 -0
- api_test_kit/scaffold.py +186 -0
- api_test_kit/templates/AGENTS.md +45 -0
- api_test_kit/templates/README.md +31 -0
- api_test_kit/templates/pyproject.toml +21 -0
- api_test_kit/templates/pytest.ini +11 -0
- api_test_kit/templates/scripts/new-endpoint.sh +75 -0
- api_test_kit/templates/tests/__init__.py +1 -0
- api_test_kit/templates/tests/conftest.py +44 -0
- api_test_toolkit-0.2.0.dist-info/METADATA +21 -0
- api_test_toolkit-0.2.0.dist-info/RECORD +26 -0
- api_test_toolkit-0.2.0.dist-info/WHEEL +5 -0
- api_test_toolkit-0.2.0.dist-info/entry_points.txt +2 -0
- api_test_toolkit-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 生成新的端点模型 + 测试文件模板
|
|
3
|
+
# 用法:./scripts/new-endpoint.sh <资源名>
|
|
4
|
+
#
|
|
5
|
+
# 示例:./scripts/new-endpoint.sh products
|
|
6
|
+
# 创建:
|
|
7
|
+
# src/{{ package_name }}/endpoints/products.py
|
|
8
|
+
# tests/endpoints/test_products.py
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
NAME="${1:?用法: $0 <资源名>}"
|
|
13
|
+
|
|
14
|
+
# 用 Python 推导类名
|
|
15
|
+
CLASS_NAME="$(python3 -c "
|
|
16
|
+
import sys
|
|
17
|
+
name = sys.argv[1]
|
|
18
|
+
if name.endswith('s'):
|
|
19
|
+
name = name[:-1]
|
|
20
|
+
parts = name.replace('-', '_').split('_')
|
|
21
|
+
result = ''.join(p.capitalize() for p in parts)
|
|
22
|
+
print(result + 'Endpoint')
|
|
23
|
+
" "$NAME")"
|
|
24
|
+
|
|
25
|
+
SRC_DIR="src/{{ package_name }}/endpoints"
|
|
26
|
+
TEST_DIR="tests/endpoints"
|
|
27
|
+
|
|
28
|
+
mkdir -p "$SRC_DIR" "$TEST_DIR"
|
|
29
|
+
|
|
30
|
+
# ── 端点模型 ────────────────────────────────────────────────
|
|
31
|
+
cat > "$SRC_DIR/$NAME.py" <<PYEOF
|
|
32
|
+
"""${CLASS_NAME} — ${NAME} 的 API 端点模型."""
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from api_test_kit.client import ApiResponse
|
|
36
|
+
from api_test_kit.endpoints._base import BaseEndpoint
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ${CLASS_NAME}(BaseEndpoint):
|
|
40
|
+
"""${NAME} 的 CRUD 操作."""
|
|
41
|
+
|
|
42
|
+
path = "/${NAME}"
|
|
43
|
+
|
|
44
|
+
# --- 自定义方法写在这里 ---
|
|
45
|
+
PYEOF
|
|
46
|
+
|
|
47
|
+
# ── 测试文件 ─────────────────────────────────────────────────
|
|
48
|
+
cat > "$TEST_DIR/test_${NAME}.py" <<PYEOF
|
|
49
|
+
"""${NAME} 端点测试."""
|
|
50
|
+
from __future__ import annotations
|
|
51
|
+
|
|
52
|
+
import pytest
|
|
53
|
+
|
|
54
|
+
from api_test_kit.assertions import assert_status, assert_ok, assert_json_has
|
|
55
|
+
from api_test_kit.endpoints.${NAME} import ${CLASS_NAME}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Test${CLASS_NAME}List:
|
|
59
|
+
"""${NAME} 列表测试."""
|
|
60
|
+
|
|
61
|
+
def test_list_success(self, client):
|
|
62
|
+
"""应返回 200 带分页结果."""
|
|
63
|
+
ep = ${CLASS_NAME}(client)
|
|
64
|
+
resp = ep.list(page=1, size=10)
|
|
65
|
+
assert_status(resp, 200)
|
|
66
|
+
assert_ok(resp)
|
|
67
|
+
assert_json_has(resp, r"\$.data.items")
|
|
68
|
+
PYEOF
|
|
69
|
+
|
|
70
|
+
# ── 完成 ─────────────────────────────────────────────────────
|
|
71
|
+
echo "✅ 已创建:"
|
|
72
|
+
echo " $SRC_DIR/$NAME.py"
|
|
73
|
+
echo " $TEST_DIR/test_${NAME}.py"
|
|
74
|
+
echo ""
|
|
75
|
+
echo "下一步:运行 pytest $TEST_DIR/test_${NAME}.py -v"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# tests/__init__.py
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""全局 fixtures。"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from api_test_kit.client import BaseClient, BearerTokenProvider
|
|
9
|
+
from api_test_kit.config import HarnessConfig
|
|
10
|
+
from api_test_kit.e2e.context import ScenarioContext
|
|
11
|
+
from api_test_kit.logger import setup_logging
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(scope="session")
|
|
15
|
+
def env_config() -> HarnessConfig:
|
|
16
|
+
"""加载测试环境配置。
|
|
17
|
+
|
|
18
|
+
通过 ``API_TEST_ENV`` 环境变量切换环境(默认: staging)。
|
|
19
|
+
"""
|
|
20
|
+
env_name = os.getenv("API_TEST_ENV", "staging")
|
|
21
|
+
return HarnessConfig.from_env(env_name)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture(scope="session")
|
|
25
|
+
def client(env_config: HarnessConfig) -> BaseClient:
|
|
26
|
+
"""已鉴权的 HTTP 客户端,session 级别复用。"""
|
|
27
|
+
setup_logging(env_config.log_level)
|
|
28
|
+
client = BaseClient(env_config)
|
|
29
|
+
token = env_config.client_secret
|
|
30
|
+
if token and env_config.auth_type in ("bearer", "api_key"):
|
|
31
|
+
client.authenticate(BearerTokenProvider(token))
|
|
32
|
+
return client
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def unauthenticated_client(env_config: HarnessConfig) -> BaseClient:
|
|
37
|
+
"""无鉴权的客户端,用于测试鉴权/错误流程。"""
|
|
38
|
+
return BaseClient(env_config)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def e2e_context() -> ScenarioContext:
|
|
43
|
+
"""每个 E2E 场景的独立上下文。"""
|
|
44
|
+
return ScenarioContext()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: api-test-toolkit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: AI 友好的 API 自动化测试工具包
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: requests>=2.31
|
|
7
|
+
Requires-Dist: pydantic<3,>=2.5
|
|
8
|
+
Requires-Dist: pydantic-settings>=2.1
|
|
9
|
+
Requires-Dist: python-dotenv>=1.0
|
|
10
|
+
Requires-Dist: jsonpath-ng>=1.6
|
|
11
|
+
Requires-Dist: deepdiff>=7.0
|
|
12
|
+
Requires-Dist: typer<1,>=0.12
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-xdist>=3.5; extra == "dev"
|
|
16
|
+
Requires-Dist: pytest-html>=4.1; extra == "dev"
|
|
17
|
+
Requires-Dist: allure-pytest>=2.13; extra == "dev"
|
|
18
|
+
Requires-Dist: responses>=0.25; extra == "dev"
|
|
19
|
+
Requires-Dist: faker>=22.0; extra == "dev"
|
|
20
|
+
Requires-Dist: ruff>=0.3; extra == "dev"
|
|
21
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
api_test_kit/__init__.py,sha256=ZI9BDQpIDWrtXM_Tib995EM-ZxSbfq6kLGb9XaPuSdg,483
|
|
2
|
+
api_test_kit/assertions.py,sha256=ET78wN_l98CLbO_s-_RsQ0z1K7igs5mjj13BxEFUeDo,4060
|
|
3
|
+
api_test_kit/cli.py,sha256=DGPhQ-LWLLvNaCHYqtsyRJ4bMq9xVBFRhyuDBTkIKkU,1296
|
|
4
|
+
api_test_kit/client.py,sha256=ychiytV8694MlWXbY36gF7HpP3Q3s5qNz-y3K7rQD8s,7923
|
|
5
|
+
api_test_kit/config.py,sha256=Y9-38f9Ir39FR8gqPVbj0lkm-pw3ZxgYRXO3fjT4QZ8,2903
|
|
6
|
+
api_test_kit/logger.py,sha256=NcfvdXvaOkTYUg7MYzfIIb5ome_15bJnyYxo0s0-6jg,760
|
|
7
|
+
api_test_kit/scaffold.py,sha256=7MK7Lk4Lvp-Dj6mi4xhxM155afn8SZnrFM11_ctG4rc,5921
|
|
8
|
+
api_test_kit/e2e/__init__.py,sha256=GRETcT34TdWBoBLzvB1ueI7xB1jQCL5bq3sxsggajgo,435
|
|
9
|
+
api_test_kit/e2e/context.py,sha256=QrWHGT9IFsoPsLTO3ui5bVd6OG5GDuSnwtsJ7OnSp5s,1997
|
|
10
|
+
api_test_kit/e2e/helpers.py,sha256=02tcX0fEtkD0MJi2VdyK5B3fjeB8lAoJ1ufdS_2E_qs,889
|
|
11
|
+
api_test_kit/e2e/scenario.py,sha256=0a0mnjCnIGCcYaFAjJsvopDEvnohgx90oPdPDkx7tjw,3500
|
|
12
|
+
api_test_kit/e2e/step.py,sha256=htGSZdPZNFxDe1DrGt3aldOSYe4m7bq5h5Elra3gcu0,2926
|
|
13
|
+
api_test_kit/endpoints/__init__.py,sha256=une6WuX1_wRCcOfl005tSb5i986lN_TP7NjF1bTGCEU,1338
|
|
14
|
+
api_test_kit/endpoints/_base.py,sha256=9BAL0a6-3vRc7-43V6SC-acznVlaNAeVHKm_gU5rlDw,1347
|
|
15
|
+
api_test_kit/templates/AGENTS.md,sha256=vadIg8o_ovYL2_fhtRyH14vpHR5LF-hZzSvyYfs8XGE,1397
|
|
16
|
+
api_test_kit/templates/README.md,sha256=tkc-Nuh2cMcp_cR5ScXhq2vDmxbIwHNH9P2DTQRdV8Y,670
|
|
17
|
+
api_test_kit/templates/pyproject.toml,sha256=7Oaq_AAf2gt9RzCBulyD3nmPUTujdzRddi8J3kTkzE8,453
|
|
18
|
+
api_test_kit/templates/pytest.ini,sha256=YGH8NZsDDUwKcDQA4DJZnrEYo6cLDAx4jeSrHmNFQ6o,238
|
|
19
|
+
api_test_kit/templates/scripts/new-endpoint.sh,sha256=oIVONvY2vR2YeUekAAMk9rAeDw4hNn2a5AH5ZSaVvxA,2318
|
|
20
|
+
api_test_kit/templates/tests/__init__.py,sha256=iViLDCvp2HIGDniqaMz5X5TKJ-pry3mkNQnWbClsc84,20
|
|
21
|
+
api_test_kit/templates/tests/conftest.py,sha256=y1itnNbVBj0oZ8uT_Ix6fTc48KsdhX19O-cOc7PvHl0,1310
|
|
22
|
+
api_test_toolkit-0.2.0.dist-info/METADATA,sha256=weM_jvp29UWChMnmCeBuN1HxGRLX264iyJSRZ9l9lNc,743
|
|
23
|
+
api_test_toolkit-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
24
|
+
api_test_toolkit-0.2.0.dist-info/entry_points.txt,sha256=7N5ZGnaCauNMusu97hWGAdAZmCbgk3v4dJGqD7kIJYo,58
|
|
25
|
+
api_test_toolkit-0.2.0.dist-info/top_level.txt,sha256=aZR715fS60fIKUfQr62k00_KEFB1BdAtUeGXxvKPe8M,13
|
|
26
|
+
api_test_toolkit-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
api_test_kit
|