İçeriğe geç

Python ile REST API Testi: requests ve pytest

T
Tolgahan
· · 12 dk okuma · 335 görüntülenme

Neden API Testi?

Modern yazılım geliştirmede REST API'ler uygulamaların omurgasını oluşturuyor. Frontend, mobil uygulama, üçüncü parti entegrasyonlar — hepsi API üzerinden haberleşiyor. Bir endpoint'in bozulması tüm sistemi etkileyebilir.

Manuel test (Postman ile tek tek istek atma) küçük projelerde işe yarar ama ölçeklenmez. Otomatik API testleri ile her commit'te tüm endpoint'ler test edilir, regression hataları anında yakalanır ve refactoring güvenle yapılabilir.

Python, API testi için mükemmel bir dildir. requests kütüphanesi HTTP isteklerini kolay hale getirir, pytest ise test framework olarak güçlü ve esnektir.

requests Kütüphanesi ile HTTP İstekleri

requests Python'un en popüler HTTP kütüphanesidir. Temel kullanım:

import requests

BASE_URL = "http://localhost:8080/api"

# GET istegi
response = requests.get(f"{BASE_URL}/users")
print(response.status_code)  # 200
print(response.json())       # JSON response body

# POST istegi
new_user = {
    "name": "Tolgahan Gencer",
    "email": "tolgahan@example.com",
    "password": "securePassword123"
}
response = requests.post(f"{BASE_URL}/users", json=new_user)
created_user = response.json()

# PUT istegi
update_data = {"name": "Tolgahan G."}
response = requests.put(
    f"{BASE_URL}/users/{created_user['id']}",
    json=update_data,
    headers={"Authorization": f"Bearer {token}"}
)

# DELETE istegi
response = requests.delete(f"{BASE_URL}/users/{created_user['id']}")

Session ile Token Yönetimi

Her istekte header eklemek yerine Session kullanabilirsiniz:

session = requests.Session()
session.headers.update({
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIs...",
    "Content-Type": "application/json"
})

# Artik her istekte header otomatik eklenir
response = session.get(f"{BASE_URL}/users")
response = session.post(f"{BASE_URL}/orders", json=order_data)

pytest ile Test Yapısı

pytest, Python'un en güçlü test framework'üdür. Basit bir test dosyası:

# tests/test_users_api.py
import requests
import pytest

BASE_URL = "http://localhost:8080/api"


class TestUsersAPI:

    def test_get_all_users(self):
        response = requests.get(f"{BASE_URL}/users")
        assert response.status_code == 200
        assert isinstance(response.json(), list)

    def test_create_user(self):
        payload = {
            "name": "Test User",
            "email": "test@example.com",
            "password": "Test1234!"
        }
        response = requests.post(f"{BASE_URL}/users", json=payload)
        assert response.status_code == 201
        data = response.json()
        assert data["name"] == "Test User"
        assert "password" not in data

    def test_get_user_not_found(self):
        response = requests.get(f"{BASE_URL}/users/999999")
        assert response.status_code == 404

    def test_create_user_invalid_email(self):
        payload = {"name": "Test", "email": "invalid", "password": "Test1234!"}
        response = requests.post(f"{BASE_URL}/users", json=payload)
        assert response.status_code == 400

pytest Fixtures ile Setup/Teardown

Fixtures, testler arasında paylaşılan setup kodunu merkezi hale getirir:

# tests/conftest.py
import pytest
import requests

BASE_URL = "http://localhost:8080/api"


@pytest.fixture(scope="session")
def api_session():
    session = requests.Session()
    login_data = {"email": "admin@example.com", "password": "Admin123!"}
    response = session.post(f"{BASE_URL}/auth/login", json=login_data)
    token = response.json()["accessToken"]
    session.headers.update({"Authorization": f"Bearer {token}"})
    return session


@pytest.fixture
def create_user(api_session):
    created_ids = []

    def _create_user(name="Test User", email=None):
        if email is None:
            import uuid
            email = f"test-{uuid.uuid4().hex[:8]}@example.com"
        payload = {"name": name, "email": email, "password": "Test1234!"}
        response = api_session.post(f"{BASE_URL}/users", json=payload)
        user = response.json()
        created_ids.append(user["id"])
        return user

    yield _create_user

    for user_id in created_ids:
        api_session.delete(f"{BASE_URL}/users/{user_id}")


@pytest.fixture
def sample_user(create_user):
    return create_user(name="Sample User")

Kullanım:

class TestUserOperations:

    def test_update_user(self, api_session, sample_user):
        user_id = sample_user["id"]
        response = api_session.put(
            f"{BASE_URL}/users/{user_id}",
            json={"name": "Updated Name"}
        )
        assert response.status_code == 200
        assert response.json()["name"] == "Updated Name"

@pytest.mark.parametrize ile Veri Odaklı Testler

Aynı testi farklı verilerle çalıştırmak için parametrize kullanın:

class TestInputValidation:

    @pytest.mark.parametrize("email,expected_status", [
        ("valid@example.com", 201),
        ("", 400),
        ("gecersiz-email", 400),
        ("user@domain.com", 201),
    ])
    def test_email_validation(self, api_session, email, expected_status):
        payload = {"name": "Test", "email": email, "password": "Test1234!"}
        response = api_session.post(f"{BASE_URL}/users", json=payload)
        assert response.status_code == expected_status

    @pytest.mark.parametrize("password,expected_status", [
        ("Short1!", 400),
        ("nouppercase1!", 400),
        ("ValidPass123!", 201),
    ])
    def test_password_validation(self, api_session, password, expected_status):
        import uuid
        payload = {
            "name": "Test",
            "email": f"test-{uuid.uuid4().hex[:8]}@example.com",
            "password": password
        }
        response = api_session.post(f"{BASE_URL}/users", json=payload)
        assert response.status_code == expected_status

Mock Server ile Bağımsız Test

Harici API bağımlılığını kaldırmak için responses kütüphanesini kullanın:

import responses
import requests

BASE_URL = "https://api.payment-provider.com"


class TestPaymentService:

    @responses.activate
    def test_successful_payment(self):
        responses.add(
            responses.POST,
            f"{BASE_URL}/charges",
            json={"id": "ch_123", "status": "succeeded", "amount": 5000},
            status=200
        )

        response = requests.post(
            f"{BASE_URL}/charges",
            json={"amount": 5000, "currency": "TRY", "source": "tok_visa"}
        )
        assert response.status_code == 200
        assert response.json()["status"] == "succeeded"

    @responses.activate
    def test_payment_failure(self):
        responses.add(
            responses.POST,
            f"{BASE_URL}/charges",
            json={"error": {"code": "card_declined"}},
            status=402
        )
        response = requests.post(f"{BASE_URL}/charges", json={"amount": 5000})
        assert response.status_code == 402

CI/CD Entegrasyonu

GitHub Actions ile her push'ta API testlerini otomatik çalıştırma:

name: API Tests
on: [push, pull_request]

jobs:
  api-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - name: Install dependencies
        run: pip install pytest requests responses
      - name: Run API tests
        run: pytest tests/ -v --tb=short --junitxml=test-results.xml

Response Validation

API yanıtlarının yapısını doğrulamak için schema validation kullanın:

def assert_user_schema(data):
    required_fields = ["id", "name", "email", "createdAt"]
    for field in required_fields:
        assert field in data, f"'{field}' alani eksik"
    assert isinstance(data["id"], int)
    assert "@" in data["email"]
    assert "password" not in data

class TestUserSchema:
    def test_response_schema(self, api_session, sample_user):
        response = api_session.get(f"{BASE_URL}/users/{sample_user['id']}")
        assert response.status_code == 200
        assert_user_schema(response.json())

Özet

  • requests kütüphanesi ile HTTP isteklerini kolay ve okunabilir şekilde yapın

  • pytest fixtures ile test setup/teardown kodunu merkezileştirin

  • parametrize ile aynı testi farklı verilerle çalıştırarak coverage artırın

  • Mock server (responses) ile harici API bağımlılıklarını ortadan kaldırın

  • CI/CD pipeline ile testleri her commit'te otomatik çalıştırın

  • Schema validation ile response yapısını doğrulayın

Paylaş:
Son güncelleme: Jun 04, 2026

Yorumlar

Giriş yapın ve yorum bırakın.

Henüz yorum yok

Düşüncelerinizi paylaşan ilk siz olun!

Bu yazıyı beğendiniz mi?

Bültene abone olun ve yeni yazılardan ilk siz haberdar olun. Spam yok, söz.

İlgili Yazılar