ΠΡΠΈΠ²Π΅Ρ! ΠΡΠΎ README ΠΏΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π½Π°ΡΠ΅Π³ΠΎ API Π΄Π»Ρ ΡΠ΅ΠΊΠ»Π°ΠΌΠ½ΠΎΠΉ ΠΏΠ»Π°ΡΡΠΎΡΠΌΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Schemathesis. ΠΡ ΡΡΡ ΡΠΎΠ±ΡΠ°Π»ΠΈ Π²ΡΠ΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎΠ΅ Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ OpenAPI ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΉ - ΠΎΡ ΠΏΡΠΎΡΡΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ Π΄ΠΎ ΠΊΠΎΠΌΠΏΠ»Π΅ΠΊΡΠ½ΡΡ ΡΡΠ΅Π½Π°ΡΠΈΠ΅Π².
ΠΡΠΎ ΡΠ΅ΡΠ΄ΡΠ΅ Π½Π°ΡΠ΅Π³ΠΎ API - ΠΏΠΎΠ΄ΡΠΎΠ±Π½Π°Ρ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ Π²ΡΠ΅Ρ ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΠΎΠ², ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ², ΠΎΡΠ²Π΅ΡΠΎΠ² ΠΈ ΠΎΡΠΈΠ±ΠΎΠΊ. Π‘ΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ ΠΎΠΏΠΈΡΡΠ²Π°Π΅Ρ:
- ΠΠ°ΠΌΠΏΠ°Π½ΠΈΠΈ: ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅, ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅, ΠΏΠ°ΡΠ·Π°/Π²ΠΎΠ·ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅
- ΠΠ΅Π½Π΄ΠΈΠ½Π³ΠΈ: ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡΠ°Π΄ΠΎΡΠ½ΡΠΌΠΈ ΡΡΡΠ°Π½ΠΈΡΠ°ΠΌΠΈ Ρ A/B ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ
- ΠΡΡΠ΅ΡΡ: Π½Π°ΡΡΡΠΎΠΉΠΊΠ° ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠΉ Ρ Π²Π΅ΡΠ°ΠΌΠΈ ΠΈ payout'Π°ΠΌΠΈ
- ΠΠ½Π°Π»ΠΈΡΠΈΠΊΠ°: Π΄Π΅ΡΠ°Π»ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ ΠΏΠΎ ΡΡΠ°ΡΠΈΠΊΡ ΠΈ ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΠΌ
- ΠΠ»ΠΈΠΊΠΈ: ΡΡΠ΅ΠΊΠΈΠ½Π³ ΡΡΠ°ΡΠΈΠΊΠ° Ρ fraud detection ΠΈ 5-level ΡΡΠ±-ΡΡΠ΅ΠΊΠΈΠ½Π³ΠΎΠΌ
Flask-ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡΠΎΡΠΎΠ΅ ΠΈΠΌΠΈΡΠΈΡΡΠ΅Ρ ΡΠ΅Π°Π»ΡΠ½ΡΠΉ API. ΠΠΎΠ»Π½ΠΎΡΡΡΡ ΡΠΎΠ²ΠΌΠ΅ΡΡΠΈΠΌΠΎ Ρ OpenAPI ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠ΅ΠΉ:
- β ΠΡΠ΅ ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΡ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ
- β ΠΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠ΅ HTTP ΠΊΠΎΠ΄Ρ ΠΎΡΠ²Π΅ΡΠΎΠ²
- β ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ ΠΏΠΎ ΡΡ Π΅ΠΌΠ°ΠΌ
- β ΠΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ (Bearer, Basic, API-Key)
- β Fraud detection Π΄Π»Ρ ΠΊΠ»ΠΈΠΊΠΎΠ²
- π ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° CORS Π΄Π»Ρ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈΠ· Π±ΡΠ°ΡΠ·Π΅ΡΠ°
Schemathesis - ΡΡΠΎ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ Π΄Π»Ρ property-based ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ REST API. ΠΠ½:
- Π§ΠΈΡΠ°Π΅Ρ OpenAPI ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ
- ΠΠ΅Π½Π΅ΡΠΈΡΡΠ΅Ρ ΡΠ΅ΡΡΠΎΠ²ΡΠ΅ Π·Π°ΠΏΡΠΎΡΡ Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ ΡΡ Π΅ΠΌ
- ΠΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ Π·Π°ΠΏΡΠΎΡΡ ΠΊ API
- ΠΡΠΎΠ²Π΅ΡΡΠ΅Ρ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠ΅ ΠΎΡΠ²Π΅ΡΠΎΠ² ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ
- ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΡΡΡΡΡ ΡΠ΅ΡΡΠΎΠ²ΡΡ ΡΠ»ΡΡΠ°Π΅Π²
- ΠΡΠΎΠ²Π΅ΡΠΊΠ° edge cases (ΠΏΡΡΡΡΠ΅ ΡΡΡΠΎΠΊΠΈ, null Π·Π½Π°ΡΠ΅Π½ΠΈΡ, Π³ΡΠ°Π½ΠΈΡΡ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ΠΎΠ²)
- Property-based testing - Π½Π°Ρ ΠΎΠ΄ΠΈΡ Π±Π°Π³ΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΡΠΎΠΏΡΡΡΡΡ ΠΎΠ±ΡΡΠ½ΡΠ΅ ΡΠ΅ΡΡΡ
- ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ pytest Π΄Π»Ρ CI/CD
- ΠΠΎΠ΄ΡΠΎΠ±Π½ΡΠ΅ ΠΎΡΡΠ΅ΡΡ ΠΎ Π½Π°ΠΉΠ΄Π΅Π½Π½ΡΡ Π½Π΅ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΡΡ
# ΠΠ· Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΈ goservik/
python run_server_g.pyΠ‘Π΅ΡΠ²Π΅Ρ Π·Π°ΠΏΡΡΡΠΈΡΡΡ Π½Π° http://127.0.0.1:8000
pip install schemathesis# Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌ Π²ΡΠ΅ ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΡ
schemathesis run openapi.yaml --base-url=http://127.0.0.1:8000/v1
# Π’ΠΎΠ»ΡΠΊΠΎ health check (Π±ΡΡΡΡΠ°Ρ ΠΏΡΠΎΠ²Π΅ΡΠΊΠ°)
schemathesis run openapi.yaml --base-url=http://127.0.0.1:8000/v1 --endpoint="/health"
# Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌ ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΠΈ
schemathesis run openapi.yaml --base-url=http://127.0.0.1:8000/v1 --endpoint="/campaigns"schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/health" \
--checks=all# Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΠΉ Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/campaigns" \
--checks=all \
--hypothesis-max-examples=50# Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌ ΠΊΠ»ΠΈΠΊΠΈ Ρ ΡΡΠ±-ΡΡΠ΅ΠΊΠΈΠ½Π³ΠΎΠΌ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/click" \
--checks=all# Π‘ Bearer ΡΠΎΠΊΠ΅Π½ΠΎΠΌ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--header="Authorization: Bearer test_jwt_token_12345"
# Π‘ API Key
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--header="X-API-Key: test_api_key_abcdef123"# Π’ΠΎΠ»ΡΠΊΠΎ GET Π·Π°ΠΏΡΠΎΡΡ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--method=GET
# ΠΠ°ΠΊΡΠΈΠΌΡΠΌ 100 ΠΏΡΠΈΠΌΠ΅ΡΠΎΠ² Π½Π° ΡΠ½Π΄ΠΏΠΎΠΈΠ½Ρ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--hypothesis-max-examples=100
# ΠΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°ΡΡ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--checks=not response_schema_conformance# JUnit XML Π΄Π»Ρ CI/CD
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--junit-xml=schemathesis-report.xml
# JSON ΠΎΡΡΠ΅Ρ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--output=schemathesis-report.json- Π‘ΡΡΡΠΊΡΡΡΠ° JSON ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΠ΅Ρ OpenAPI ΡΡ Π΅ΠΌΠ΅
- Π’ΠΈΠΏΡ Π΄Π°Π½Π½ΡΡ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠ΅ (string, number, boolean, etc.)
- ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΏΠΎΠ»Ρ ΠΏΡΠΈΡΡΡΡΡΠ²ΡΡΡ
- Π€ΠΎΡΠΌΠ°ΡΡ Π²Π°Π»ΠΈΠ΄Π½Ρ (email, date-time, UUID)
- ΠΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠ΅ ΠΊΠΎΠ΄Ρ Π΄Π»Ρ ΡΡΠΏΠ΅ΡΠ½ΡΡ ΠΎΡΠ²Π΅ΡΠΎΠ²
- ΠΠΎΡΡΠ΅ΠΊΡΠ½ΡΠ΅ ΠΊΠΎΠ΄Ρ ΠΎΡΠΈΠ±ΠΎΠΊ (400, 401, 404, 500)
- ΠΠ°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ
- Query ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π² ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎΠΌ ΡΠΎΡΠΌΠ°ΡΠ΅
- Path ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π²Π°Π»ΠΈΠ΄Π½Ρ
- Request body ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΠ΅Ρ ΡΡ Π΅ΠΌΠ΅
- ΠΡΡΡΡΠ΅ ΡΡΡΠΎΠΊΠΈ ΠΈ null Π·Π½Π°ΡΠ΅Π½ΠΈΡ
- ΠΡΠ°Π½ΠΈΡΠ½ΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ (min/max)
- Π‘ΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΡΠ΅ ΡΠΈΠΌΠ²ΠΎΠ»Ρ
- ΠΡΠ΅Π½Ρ Π΄Π»ΠΈΠ½Π½ΡΠ΅ ΡΡΡΠΎΠΊΠΈ
# Π‘Π΅ΡΠ²Π΅Ρ Π½Π΅ Π·Π°ΠΏΡΡΠ΅Π½ - Π·Π°ΠΏΡΡΡΠΈ Π΅Π³ΠΎ!
python run_server_g.py# ΠΠΎΠ±Π°Π²Ρ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ Π΄Π»Ρ Π·Π°ΡΠΈΡΠ΅Π½Π½ΡΡ
ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΠΎΠ²
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--header="Authorization: Bearer test_jwt_token_12345"# ΠΠ³ΡΠ°Π½ΠΈΡΡ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΏΡΠΈΠΌΠ΅ΡΠΎΠ²
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--hypothesis-max-examples=20name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install schemathesis flask gunicorn
- name: Start mock server
run: |
python run_server_g.py &
sleep 5
- name: Run Schemathesis tests
run: |
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--junit-xml=schemathesis-report.xml \
--hypothesis-max-examples=50
- name: Upload test results
uses: actions/upload-artifact@v2
if: always()
with:
name: schemathesis-results
path: schemathesis-report.xml# Π‘Π½Π°ΡΠ°Π»Π° ΠΏΡΠΎΡΠ΅ΡΡΠΈΡΡΠΉ ΠΎΠ΄ΠΈΠ½ ΡΠ½Π΄ΠΏΠΎΠΈΠ½Ρ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/health"# Public endpoints (Π±Π΅Π· auth)
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/health"
# Bearer token endpoints
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/campaigns" \
--header="Authorization: Bearer test_jwt_token_12345"
# API Key endpoints
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--endpoint="/clicks" \
--header="X-API-Key: test_api_key_abcdef123"# Π‘ΠΌΠΎΡΡΠΈ ΠΊΠ°ΠΊΠΈΠ΅ ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΡ ΠΏΡΠΎΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½Ρ
schemathesis run openapi.yaml \
--base-url=http://127.0.0.1:8000/v1 \
--show-errors-tracebacks \
--verbosity=verboseSchemathesis - ΡΡΠΎ ΠΌΠΎΡΠ½ΡΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ API. ΠΠ½ Π½Π°Ρ ΠΎΠ΄ΠΈΡ Π±Π°Π³ΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ Π»Π΅Π³ΠΊΠΎ ΠΏΡΠΎΠΏΡΡΡΠΈΡΡ ΠΏΡΠΈ ΡΡΡΠ½ΠΎΠΌ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ, ΠΈ Π³Π°ΡΠ°Π½ΡΠΈΡΡΠ΅Ρ, ΡΡΠΎ ΡΠ²ΠΎΠΉ API Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΠ΅Ρ OpenAPI ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ.
Mock ΡΠ΅ΡΠ²Π΅Ρ Π² ΡΡΠΎΠΌ ΠΏΡΠΎΠ΅ΠΊΡΠ΅ ΠΈΠ΄Π΅Π°Π»ΡΠ½ΠΎ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΠΈΡ Π΄Π»Ρ:
- Π Π°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ API (TDD ΠΏΠΎΠ΄Ρ ΠΎΠ΄)
- Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠ²
- ΠΠ΅ΠΌΠΎ ΠΈ ΠΏΡΠ΅Π·Π΅Π½ΡΠ°ΡΠΈΠΉ
- CI/CD ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ΠΎΠ²
Π£Π΄Π°ΡΠΈ Π² ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ! ΠΡΠ»ΠΈ ΡΡΠΎ-ΡΠΎ ΠΏΠΎΠΉΠ΄Π΅Ρ Π½Π΅ ΡΠ°ΠΊ - ΠΏΡΠΎΠ²Π΅ΡΡΠΉ Π»ΠΎΠ³ΠΈ ΡΠ΅ΡΠ²Π΅ΡΠ° ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉ --show-errors-tracebacks Π΄Π»Ρ Π΄Π΅ΡΠ°Π»ΡΠ½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ. π