Python geliştiricileri pytest'i tercih eder çünkü o, işleri kolaylaştırır. Bir test sadece adı test_ ile başlayan bir fonksiyondur, bir doğrulama basit bir assert ifadesidir ve gerisini çalıştırıcı halleder. Onu requests kütüphanesiyle eşleştirin ve ağırbaşlı törenlere gerek kalmadan API testlerini otomatikleştirmek için eksiksiz, kod-öncelikli bir çerçeveye sahip olursunuz.
Bu eğitim, gerçek bir pytest API test paketi oluşturmayı göstermektedir. Projeyi kuracak, ilk istek testinizi yazacak, kurulum mantığını fixture'lar ile paylaşacak, parametrize ile aynı testi birçok girdiyle çalıştıracak ve yanıt durumunu, gövdesini ve JSON Şemasını doğrulayacaksınız. Her örnek gerçekçi, herkese açık tarzda bir API kullanır, böylece kodu doğrudan uyarlayabilirsiniz.
Projenin Kurulumu
İhtiyacınız olan iki kütüphaneyi sanal bir ortama yükleyin:
python -m venv .venv
source .venv/bin/activate
pip install pytest requests jsonschema
Temiz bir düzen, paket büyüdükçe sürdürülebilir kalmasını sağlar:
api-tests/
conftest.py # shared fixtures
test_users.py # tests for the users endpoints
test_orders.py # tests for the orders endpoints
pytest.ini # configuration
Pytest testleri otomatik olarak keşfeder. Dosyalar test_ ile başlamalı veya _test.py ile bitmeli, fonksiyonlar test_ ile başlamalı ve test sınıfları Test ile başlamalı ve __init__ metoduna sahip olmamalıdır. Bu kurallara uyarsanız, keşfetmeyi asla manuel olarak yapılandırmanıza gerek kalmaz. Otomatik test disiplini sizin için yeniyse, otomatik testin ne olduğu hakkındaki başlangıç rehberimiz size bağlam sağlar.
API testi için neden özellikle pytest? requests kütüphanesi HTTP'yi yönetirken, pytest bunun etrafındaki her şeyi halleder: keşif, okunabilir hata çıktısı ile doğrulamalar, fixture'lar aracılığıyla kurulum ve temizlik, parametrize aracılığıyla veri odaklı çalıştırmalar ve raporlama. Ekibinizin uygulamanın kendisi için muhtemelen zaten kullandığı bir dilde, iki küçük, iyi belgelenmiş kütüphaneden eksiksiz bir API otomasyon çerçevesi oluşturursunuz. Bu yakınlık önemlidir. Kodla aynı depoda yaşayan testler dürüst kalır, çünkü bozan bir değişiklik ve başarısız testi aynı pull request'te görünür.
İlk API Testinizi Yazma
Bir pytest API testi bir istek gönderir ve yanıtı doğrular. İşte bir kullanıcı uç noktasına karşı bir test:
import requests
BASE_URL = "https://api.example.com/v1"
def test_get_user_returns_200():
response = requests.get(f"{BASE_URL}/users/42")
assert response.status_code == 200
def test_get_user_returns_expected_fields():
response = requests.get(f"{BASE_URL}/users/42")
body = response.json()
assert body["id"] == 42
assert "email" in body
assert body["status"] == "active"
Paketi pytest -v ile çalıştırın. Başarısız olan her assert, gerçek değeri gösteren ayrıntılı bir rapor üretir ki bu, pytest'in en iyi özelliklerinden biridir. Özel doğrulama metotlarına ihtiyacınız yoktur; çerçeve, zengin çıktı sağlamak için düz assert ifadelerini yeniden yazar. Bir yanıt üzerinde yapmaya değer daha geniş kontroller için, API doğrulamaları kılavuzumuza bakın.
Kurulumu Fixture'lar ile Paylaşma
Her testte temel URL'yi ve bir HTTP oturumunu tekrarlamak israftır. Fixture'lar bunu çözer. Bir fixture, @pytest.fixture ile işaretlenmiş, testlerin parametre olarak adlandırarak isteyebileceği bir değer üreten bir fonksiyondur.
Paylaşılan fixture'ları conftest.py dosyasına koyun, böylece her test dosyası bunları içe aktarmaya gerek kalmadan kullanabilir:
# conftest.py
import pytest
import requests
BASE_URL = "https://api.example.com/v1"
@pytest.fixture(scope="session")
def api_session():
session = requests.Session()
session.headers.update({"Accept": "application/json"})
yield session
session.close()
@pytest.fixture
def auth_token(api_session):
response = api_session.post(
f"{BASE_URL}/auth/login",
json={"email": "qa@example.com", "password": "test-pass"},
)
return response.json()["token"]
scope="session" argümanı, oturumun her test başına değil, tüm çalıştırma için bir kez oluşturulduğu anlamına gelir. yield anahtar kelimesi, kurulumu temizlikten ayırır: yield öncesindeki kod önce çalışır, sonrasındaki kod ise fixture kapsam dışına çıktığında çalışır. Bir test, sadece ihtiyacı olanı ister:
def test_create_order(api_session, auth_token):
response = api_session.post(
f"{BASE_URL}/orders",
headers={"Authorization": f"Bearer {auth_token}"},
json={"product_id": 7, "quantity": 2},
)
assert response.status_code == 201
assert response.json()["status"] == "pending"
Fixtures, pytest'in eski setup_function ve teardown_function tarzı için modern bir yerine geçme yöntemidir. Temiz bir şekilde bir araya gelirler, kapsamları desteklerler ve bağımlılıkları açık hale getirirler; bu yüzden resmi pytest fixture'lar dokümantasyonu onları varsayılan yaklaşım olarak önermektedir.
Bir Testi Birçok Girdiyle Çalıştırma
API uç noktalarının genellikle birçok girdiyle kontrol edilmesi gerekir: geçerli değerler, geçersiz değerler ve uç durumlar. Her biri için ayrı bir fonksiyon yazmak zahmetlidir. @pytest.mark.parametrize dekoratörü, bir test gövdesini bir girdi listesine karşı çalıştırır:
import pytest
import requests
BASE_URL = "https://api.example.com/v1"
@pytest.mark.parametrize("user_id,expected_status", [
(42, 200),
(99999, 404),
(0, 404),
(-1, 400),
])
def test_get_user_status_codes(api_session, user_id, expected_status):
response = api_session.get(f"{BASE_URL}/users/{user_id}")
assert response.status_code == expected_status
Bu, tek bir fonksiyondan dört ayrı test durumu üretir. Her biri bağımsız olarak çalışır ve raporlanır, bu nedenle tek bir kötü girdi diğerlerini gizlemez. Parametrize, pytest'in veri odaklı test etmeye yerleşik yanıtıdır. Girdi kümesi büyüdüğünde, onu bir dosyadan yüklemek yerine; CSV ve JSON ile veri odaklı API testi rehberimiz bu deseni kapsar. Her girdinin hangi durum kodunu döndürmesi gerektiğinden emin değilseniz, REST API'lerinin kullanması gereken HTTP durum kodları hakkındaki referans yararlı bir yardımcıdır.
Yanıt Gövdesi ve Şeması Üzerine Doğrulama
Durum kodları gerekli ancak yeterli değildir. Bozuk bir gövdeye sahip 200 yanıtı hala bir hatadır. Ayrıştırılmış JSON üzerinde doğrudan doğrulama yapın:
def test_order_response_shape(api_session, auth_token):
response = api_session.post(
f"{BASE_URL}/orders",
headers={"Authorization": f"Bearer {auth_token}"},
json={"product_id": 7, "quantity": 2},
)
body = response.json()
assert isinstance(body["id"], int)
assert body["quantity"] == 2
assert body["total"] > 0
assert response.elapsed.total_seconds() < 1.0
Daha güçlü garantiler için, gövdeyi bir JSON Şemasına göre doğrulayın. Bu, elle yazılan kontrollerin kaçırabileceği, yeniden adlandırılmış veya eksik bir alan gibi yapısal kaymaları yakalar:
from jsonschema import validate
order_schema = {
"type": "object",
"required": ["id", "product_id", "quantity", "status", "total"],
"properties": {
"id": {"type": "integer"},
"product_id": {"type": "integer"},
"quantity": {"type": "integer", "minimum": 1},
"status": {"type": "string"},
"total": {"type": "number"},
},
}
def test_order_matches_schema(api_session, auth_token):
response = api_session.post(
f"{BASE_URL}/orders",
headers={"Authorization": f"Bearer {auth_token}"},
json={"product_id": 7, "quantity": 2},
)
validate(instance=response.json(), schema=order_schema)
Şema doğrulaması, alan bazında doğrulamalardan daha iyi ölçeklenir çünkü tek bir şema tüm yanıt yapısını kapsar. jsonschema kütüphanesi standart bir tercihtir ve doğrulama dokümantasyonu desteklenen anahtar kelimeleri açıklar.
Paketi CI'da Çalıştırma
Bir pytest paketi, otomatik olarak çalıştığında değerini kanıtlar. Pytest, bir hata durumunda sıfır olmayan bir çıkış kodu döndürür ki bu, bir CI sunucusunun bir derlemeyi başarısız etmesi için tam olarak ihtiyacı olan şeydir. Satır içi görüntüleme için bir JUnit raporu yayınlayın:
pytest -v --junitxml=results.xml
Bu komutu bir GitHub Actions adımına veya başka herhangi bir pipeline'a bağlayın ve API testleriniz her commit'i denetlesin. CI/CD pipeline'larındaki API testleri hakkındaki rehberimiz, token'lar için secret enjeksiyonu ve ortam seçimi dahil olmak üzere tam kurulumu göstermektedir.
İki CI alışkanlığı, bir pytest paketini güvenilir kılar. Birincisi, gizli bilgileri veya ortam URL'lerini test dosyalarına asla sabit kodlamayın. Bunları ortam değişkenlerinden okuyun, böylece aynı paket CI'da hazırlık ortamına ve yerel olarak düzenleme yapmadan çalışabilir:
import os
BASE_URL = os.environ.get("API_BASE_URL", "https://staging.example.com/v1")
İkincisi, geri bildirimi hızlı tutmak için bağımsız testleri paralel olarak çalıştırın. pytest-xdist eklentisi, pytest -n auto ile testleri CPU çekirdeklerine dağıtır. Paralel çalıştırmalar yalnızca testleriniz durumu paylaşmıyorsa işe yarar ki bu da test veri katmanının neden önemli olduğunun bir başka nedenidir. Çalıştırma sırasına bağlı olan bir paket, paralel çalıştığı anda öngörülemeyen bir şekilde başarısız olacaktır.
Bir pytest Paketini Sürdürülebilir Tutmak
Elli testlik bir paket kolaydır. Beş yüz testlik bir paket disiplin gerektirir. Üç uygulama, büyüdükçe bir pytest API çerçevesini sağlıklı tutar.
İlgili testleri modüller halinde gruplayın ve sınıfları sadece kurulumu paylaştıklarında kullanın, süsleme için değil. Açık bir fonksiyon setine sahip test_orders.py dosyası, tek bir devasa dosyadan daha iyi okunur. pytest.ini dosyasında kaydedilen işaretleyicileri kullanarak testleri etiketleyin, böylece alt kümeleri çalıştırabilirsiniz: hızlı bir kontrol için @pytest.mark.smoke, tam tarama için @pytest.mark.slow. Her commit'te smoke setini ve her gece tam seti çalıştırın.
Yapılandırmayı merkezileştirin. Temel URL'ler, şemalar ve paylaşılan fixture'lar conftest.py veya küçük bir yapılandırma modülünde bulunmalıdır, asla dosyalar arasında kopyala-yapıştır yapılmamalıdır. Hazırlık ortamı URL'si değiştiğinde, sadece bir satırı düzenlemeniz gerekir. Herhangi bir çerçeveye uygulanan, otomatik test betikleri yazma rehberimizde ele alınan aynı modüler disiplin burada da geçerlidir: iki kez yazdığınız her şeyi bir fixture'a veya yardımcı fonksiyona çıkarın.
Bunun Yerine Ne Zaman Bir Platforma Başvurmalı
Bir pytest çerçevesi, ekibiniz Python yazdığında ve testlerin uygulama kodunun yanında yaşamasını istediğinde mükemmeldir. QA veya ürün personelinin katkıda bulunması gerektiğinde veya yapıştırıcı kodunu sürdürmeden test tasarımını, mocking'i ve yürütmeyi tek bir yerde istediğinizde daha az kullanışlıdır.
Apidog bu boşluğu kapatır. Görsel test oluşturma, OpenAPI spesifikasyonunuza karşı şema doğrulaması, CSV ve JSON'dan veri odaklı çalıştırmalar ve CI için bir CLI çalıştırıcısı sunar; tüm bunlar fixture ve doğrulama kodunu manuel olarak yazmadan yapılır. Birçok ekip her ikisini de kullanır: mantık ağırlıklı senaryolar için pytest'i ve geniş kapsam ve pytest paketinin test ettiği API'leri tasarlamak ve mock'lamak için Apidog'u. Apidog'u indirebilir ve iki yaklaşımı gerçek bir uç nokta üzerinde bir öğleden sonra karşılaştırabilirsiniz.
Sıkça Sorulan Sorular
API Testi İçin Python'ın Yerleşik unittest'i Yerine Neden pytest Kullanılmalı?
Pytest daha az kalıp kod gerektirir. Testler düz fonksiyonlardır, doğrulamalar zengin hata çıktısı veren düz assert ifadeleridir ve fixture'lar kurulumu unittest'in sınıf tabanlı metotlarından daha esnek bir şekilde yönetir. Pytest ayrıca geniş bir eklenti ekosistemine ve veri odaklı testler için yerleşik parametrize'a sahiptir. Mevcut unittest tarzı testleri de çalıştırabilir, bu nedenle geçiş riski düşüktür.
Fixture ve Parametrize Arasındaki Fark Nedir?
Bir fixture, bir HTTP oturumu veya bir yetkilendirme token'ı gibi yeniden kullanılabilir bir kaynağı, onu talep eden herhangi bir teste sağlar. Parametrize, aynı test gövdesini farklı girdi değerlerine karşı birden çok kez çalıştırır. Fixture'lar kurulumu paylaşır; parametrize durumları çoğaltır. İyi bir şekilde birleşirler: parametrelendirilmiş bir test hala fixture'lara bağımlı olabilir.
Pytest API Testlerinde Yanıt Süresini Doğrulama Yapmalı mıyım?
response.elapsed.total_seconds() kullanarak yapabilirsiniz ve gevşek bir üst sınır, büyük gerilemeleri yakalar. Ancak pytest bir fonksiyonel test aracıdır, bir yük test aracı değildir. Gerçek performans çalışmaları için özel bir araç kullanın. Normal ağ değişkenliğinin istikrarsız hatalara neden olmaması için zamanlama doğrulamalarını cömert tutun.
Pytest'te API Testlerini Nasıl Bağımsız Tutarım?
Her teste, kaynakları oluşturan ve temizleyen fixture'lar aracılığıyla kendi verilerini verin ve test yürütme sırasına güvenmekten kaçının. Pytest varsayılan olarak testleri dosya sırasına göre çalıştırır, ancak iyi tasarlanmış bir paket buna bağlı olmamalıdır. Bağımsız testler paralel olarak çalışabilir ve izole bir şekilde başarısız olabilir, bu da hata ayıklamayı çok daha kolay hale getirir.
Pytest Yanıtları Bir OpenAPI Spesifikasyonuna Göre Doğrulayabilir mi?
Pytest'in kendisi bunu yapmaz, ancak jsonschema kütüphanesiyle bir JSON Şemasına göre doğrulama yapabilirsiniz ve yanıtları bir OpenAPI belgesine göre kontrol eden eklentiler mevcuttur. Şema doğrulaması iş akışınızın merkezindeyse, OpenAPI spesifikasyonunuza karşı otomatik olarak doğrulama yapan Apidog gibi bir platform, eklenti kurulumundan sizi kurtarabilir.
