client.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. """Express PC API 测试客户端(统一响应契约)"""
  2. from __future__ import annotations
  3. from typing import Any
  4. import requests
  5. class ApiClient:
  6. def __init__(self, base_url: str):
  7. self.base = base_url.rstrip("/")
  8. self.session = requests.Session()
  9. self.session.headers.update({"Content-Type": "application/json"})
  10. def url(self, path: str) -> str:
  11. if not path.startswith("/"):
  12. path = f"/{path}"
  13. return f"{self.base}{path}"
  14. def get(self, path: str, **kwargs: Any) -> requests.Response:
  15. return self.session.get(self.url(path), timeout=30, **kwargs)
  16. def post(self, path: str, json: Any = None, **kwargs: Any) -> requests.Response:
  17. return self.session.post(self.url(path), json=json, timeout=30, **kwargs)
  18. def put(self, path: str, json: Any = None, **kwargs: Any) -> requests.Response:
  19. return self.session.put(self.url(path), json=json, timeout=30, **kwargs)
  20. def delete(self, path: str, **kwargs: Any) -> requests.Response:
  21. return self.session.delete(self.url(path), timeout=30, **kwargs)
  22. @staticmethod
  23. def parse_json(resp: requests.Response) -> dict[str, Any]:
  24. return resp.json()
  25. def assert_success(self, resp: requests.Response, status: int = 200) -> Any:
  26. assert resp.status_code == status, resp.text
  27. body = self.parse_json(resp)
  28. assert body.get("success") is True, body
  29. assert body.get("error") is None, body
  30. return body.get("data")
  31. def assert_error(self, resp: requests.Response, status: int, code: str | None = None) -> dict:
  32. assert resp.status_code == status, resp.text
  33. body = self.parse_json(resp)
  34. assert body.get("success") is False, body
  35. err = body.get("error") or {}
  36. if code:
  37. assert err.get("code") == code, body
  38. return err