Robot Framework ile Python Test Otomasyonu: Kapsamlı Bir Rehber
Üretim ortamında bir hata yakaladığınızda, o hatanın neden test aşamasında yakalanmadığını sorgularsınız. Çoğu zaman cevap basittir: testler ya yazılmamıştır ya da yazılmış ama koşturulmamıştır. Robot Framework tam bu noktada devreye giriyor ve test otomasyonunu sadece geliştiricilerin değil, QA mühendislerinin ve hatta kısmen sistem yöneticilerinin de anlayabileceği bir dile çeviriyor.
Ben birkaç yıldır hem Python tabanlı pytest/unittest hem de Robot Framework kullanan ekiplerde çalıştım. Her ikisinin de güçlü yanları var, ama Robot Framework’ün özellikle keyword-driven yaklaşımı, farklı teknik seviyelerdeki ekip üyelerini aynı test sürecine dahil etmek için eşsiz bir avantaj sunuyor. Bu yazıda Robot Framework’ü sıfırdan kurarak gerçek dünya senaryolarında nasıl kullanacağınızı, Python ile nasıl entegre edeceğinizi ve pytest ile birlikte nasıl çalıştırabileceğinizi ele alacağım.
Robot Framework Nedir ve Neden Kullanmalısınız
Robot Framework, Python tabanlı açık kaynaklı bir kabul testi ve otomasyon çerçevesidir. Ama onu özel kılan şey mimarisi değil, keyword-driven testing felsefesi. Testlerinizi neredeyse İngilizce cümle yazar gibi tanımlayabilirsiniz. Bu sayede “Bu test ne yapıyor?” sorusunun cevabını anlamak için koda bakmanıza gerek kalmaz.
pytest ile karşılaştırdığınızda şunu görürsünüz: pytest mükemmel bir birim test ve entegrasyon test aracıdır, Python bilgisi gerektirir ve geliştiricilere yöneliktir. Robot Framework ise sistem testleri, kabul testleri ve end-to-end senaryolar için daha uygun bir yapı sunar. Zaten bu ikisini birbirinin rakibi olarak görmemek gerekir. Birçok ekip her iki aracı aynı anda kullanır: pytest ile birim testleri, Robot Framework ile yüksek seviyeli kabul testleri.
Kurulum ve İlk Adımlar
Temel kurulum oldukça basit. Önce bir sanal ortam oluşturup gerekli paketleri yükleyelim:
python3 -m venv rf-env
source rf-env/bin/activate # Windows: rf-envScriptsactivate
pip install robotframework
pip install robotframework-requests # HTTP testleri için
pip install robotframework-seleniumlibrary # Web UI testleri için
pip install pytest-robotframework # pytest entegrasyonu için
# Kurulumu doğrula
robot --version
Proje yapınızı şu şekilde organize etmenizi öneririm:
mkdir -p rf-project/{tests,resources,libraries,results}
cd rf-project
# Dizin yapısı
# tests/ -> .robot test dosyaları
# resources/ -> ortak keyword ve değişken tanımları
# libraries/ -> özel Python kütüphaneleri
# results/ -> test çıktıları
İlk Robot Test Dosyası
Robot Framework testleri .robot uzantılı dosyalarda yazılır. Bu dosyalar birkaç bölümden oluşur: Settings , Variables , Test Cases ve Keywords . Basit bir örnekle başlayalım:
# tests/ilk_test.robot
*** Settings ***
Documentation İlk Robot Framework test süiti
Library OperatingSystem
Library String
*** Variables ***
${PROJE_ADI} SystemX
${VERSION} 2.0
*** Test Cases ***
Basit Matematiksel Doğrulama
[Documentation] Temel aritmetik işlemleri doğrular
${sonuc}= Evaluate 2 + 2
Should Be Equal As Numbers ${sonuc} 4
Log Toplama işlemi başarılı: ${sonuc}
Değişken Birleştirme Testi
[Documentation] String işlemlerini doğrular
${tam_isim}= Catenate ${PROJE_ADI} - ${VERSION}
Should Contain ${tam_isim} SystemX
Length Should Be ${tam_isim} 13
Dosya Sistemi Kontrolü
[Documentation] Geçici dizinin var olduğunu kontrol eder
Directory Should Exist /tmp
${dosyalar}= List Files In Directory /tmp
Log /tmp dizinindeki dosya sayısı: ${dosyalar}
Bu testi çalıştırmak için:
robot --outputdir results tests/ilk_test.robot
# Belirli bir test case çalıştırmak için
robot --test "Basit Matematiksel Doğrulama" tests/ilk_test.robot
# Tag ile filtreleme
robot --include smoke tests/
Özel Python Kütüphanesi Yazmak
Robot Framework’ün gerçek gücü özel kütüphaneler yazmaya başladığınızda ortaya çıkıyor. Python ile yazdığınız herhangi bir sınıf veya fonksiyon koleksiyonunu Robot keyword’üne dönüştürebilirsiniz:
# libraries/sunucu_kontrol.py
import subprocess
import socket
import os
from robot.api.deco import keyword, library
@library(scope='SUITE')
class SunucuKontrol:
"""Sistem yönetimi testleri için özel kütüphane."""
ROBOT_LIBRARY_DOC_FORMAT = 'reST'
def __init__(self, varsayilan_timeout=30):
self.varsayilan_timeout = varsayilan_timeout
@keyword('Port Açık Mı Kontrol Et')
def port_acik_mi(self, host, port, timeout=None):
"""Verilen host ve portta bağlantı kurulabilir mi kontrol eder."""
timeout = timeout or self.varsayilan_timeout
try:
with socket.create_connection((host, int(port)), timeout=float(timeout)):
return True
except (socket.timeout, ConnectionRefusedError, OSError) as e:
raise AssertionError(f"{host}:{port} portu erişilebilir değil: {e}")
@keyword('Servis Durumunu Al')
def servis_durumu_al(self, servis_adi):
"""Systemd servisinin durumunu döner."""
sonuc = subprocess.run(
['systemctl', 'is-active', servis_adi],
capture_output=True,
text=True
)
return sonuc.stdout.strip()
@keyword('Servis Aktif Olmalı')
def servis_aktif_olmali(self, servis_adi):
"""Servisin active durumda olduğunu doğrular."""
durum = self.servis_durumu_al(servis_adi)
if durum != 'active':
raise AssertionError(
f"'{servis_adi}' servisi aktif değil. Mevcut durum: {durum}"
)
@keyword('Disk Kullanımı Kontrol Et')
def disk_kullanimi_kontrol_et(self, yol='/', maksimum_yuzde=80):
"""Disk kullanımının belirtilen eşiğin altında olduğunu doğrular."""
import shutil
toplam, kullanilan, bos = shutil.disk_usage(yol)
yuzde = (kullanilan / toplam) * 100
if yuzde > float(maksimum_yuzde):
raise AssertionError(
f"{yol} disk kullanımı %{yuzde:.1f} ile eşiği aşıyor (maks: %{maksimum_yuzde})"
)
return round(yuzde, 2)
Bu kütüphaneyi kullanan bir test dosyası:
# tests/sunucu_saglik_testleri.robot
*** Settings ***
Documentation Sunucu sağlık kontrolleri
Library ../libraries/sunucu_kontrol.py varsayilan_timeout=10
Library Collections
*** Variables ***
${YEREL_HOST} localhost
${HTTP_PORT} 80
${SSH_PORT} 22
*** Test Cases ***
Kritik Portlar Erişilebilir Olmalı
[Documentation] Temel ağ servislerinin portlarını kontrol eder
[Tags] network smoke
Port Açık Mı Kontrol Et ${YEREL_HOST} ${SSH_PORT}
Log SSH portu erişilebilir
Disk Kullanımı Kritik Seviyede Değil
[Documentation] Ana bölümlerin disk doluluk oranını kontrol eder
[Tags] disk smoke
${kullanim}= Disk Kullanımı Kontrol Et / 85
Log Kök bölüm disk kullanımı: %${kullanim}
${kullanim_var}= Disk Kullanımı Kontrol Et /var 90
Log /var disk kullanımı: %${kullanim_var}
SSH Servisi Aktif Olmalı
[Documentation] SSH daemon durumunu doğrular
[Tags] service smoke
Servis Aktif Olmalı ssh
Resource Dosyaları ve Keyword Yeniden Kullanımı
Büyük test projelerinde ortak keyword’leri ve değişkenleri ayrı resource dosyalarında tutmak, bakımı ciddi ölçüde kolaylaştırır:
# resources/ortak_keywordlar.resource
*** Settings ***
Documentation Tüm testlerde kullanılabilecek ortak keyword'ler
Library RequestsLibrary
Library Collections
Library DateTime
*** Variables ***
${API_BASE_URL} http://localhost:8080/api/v1
${ADMIN_USER} admin
${ADMIN_PASS} secret123
${ZAMAN_ASIMI} 30
*** Keywords ***
API Oturumu Başlat
[Documentation] API testleri için oturum oluşturur
[Arguments] ${base_url}=${API_BASE_URL}
Create Session api_oturumu ${base_url} timeout=${ZAMAN_ASIMI}
[Return] api_oturumu
HTTP GET İsteği At
[Documentation] GET isteği gönderir ve yanıtı döner
[Arguments] ${endpoint} ${beklenen_durum}=200
${yanit}= GET On Session api_oturumu ${endpoint}
Status Code Should Be ${yanit.status_code} ${beklenen_durum}
[Return] ${yanit}
Zaman Damgası Al
[Documentation] İnsan okunabilir zaman damgası döner
${zaman}= Get Current Date result_format=%Y-%m-%d %H:%M:%S
[Return] ${zaman}
Suite Kurulumu Yap
[Documentation] Test suite başlangıcında yapılacak hazırlıklar
Log Test suite başladı: ${SUITE NAME}
${baslangic}= Zaman Damgası Al
Set Suite Variable ${SUITE_BASLANGIC} ${baslangic}
Suite Temizliği Yap
[Documentation] Test suite sonunda temizlik işlemleri
${bitis}= Zaman Damgası Al
Log Test suite tamamlandı. Başlangıç: ${SUITE_BASLANGIC}, Bitiş: ${bitis}
API Test Senaryosu
Gerçek dünyada en çok kullandığım senaryolardan biri REST API testleri. RequestsLibrary ile bunu yapmak oldukça temiz:
# tests/api_testleri.robot
*** Settings ***
Documentation REST API entegrasyon testleri
Resource ../resources/ortak_keywordlar.resource
Library RequestsLibrary
Library JSONLibrary
Suite Setup Suite Kurulumu Yap
Suite Teardown Suite Temizliği Yap
Test Setup API Oturumu Başlat
*** Variables ***
${KULLANICI_ENDPOINT} /users
${SAGLIK_ENDPOINT} /health
*** Test Cases ***
API Sağlık Kontrolü
[Documentation] Servisin ayakta olduğunu doğrular
[Tags] smoke health
${yanit}= HTTP GET İsteği At ${SAGLIK_ENDPOINT}
${json}= Set Variable ${yanit.json()}
Should Be Equal ${json}[status] ok
Log API sağlık durumu: ${json}[status]
Kullanıcı Listesi Alınabilmeli
[Documentation] Kullanıcı listeleme endpoint'ini doğrular
[Tags] regression users
${yanit}= HTTP GET İsteği At ${KULLANICI_ENDPOINT}
${kullanici_listesi}= Set Variable ${yanit.json()}
Should Not Be Empty ${kullanici_listesi}
Length Should Be Greater ${kullanici_listesi} 0
Log Toplam kullanıcı sayısı: ${kullanici_listesi.__len__()}
Yeni Kullanıcı Oluşturulabilmeli
[Documentation] POST endpoint'i ile kullanıcı oluşturma
[Tags] regression users create
${yeni_kullanici}= Create Dictionary
... username=test_kullanici
... [email protected]
... role=viewer
${yanit}= POST On Session api_oturumu
... ${KULLANICI_ENDPOINT}
... json=${yeni_kullanici}
Should Be Equal As Integers ${yanit.status_code} 201
${olusturulan}= Set Variable ${yanit.json()}
Should Be Equal ${olusturulan}[username] test_kullanici
Set Suite Variable ${OLUSTURULAN_KULLANICI_ID} ${olusturulan}[id]
Oluşturulan Kullanıcı Silinebilmeli
[Documentation] Önceki testte oluşturulan kullanıcıyı temizler
[Tags] regression users delete
[Setup] Run Keyword If '${OLUSTURULAN_KULLANICI_ID}' == '${EMPTY}' Skip
${endpoint}= Catenate SEPARATOR= ${KULLANICI_ENDPOINT} / ${OLUSTURULAN_KULLANICI_ID}
${yanit}= DELETE On Session api_oturumu ${endpoint}
Should Be Equal As Integers ${yanit.status_code} 204
pytest ile Robot Framework Entegrasyonu
Bazı ekipler pytest altyapısını korurken Robot Framework testlerini de aynı pipeline’a dahil etmek ister. pytest-robotframework paketi tam burada devreye giriyor:
# pytest ile robot testlerini çalıştırmak
pip install pytest-robotframework
# pytest.ini veya pyproject.toml yapılandırması
cat > pytest.ini << 'EOF'
[pytest]
addopts = --robot-outputdir=results
testpaths = tests
EOF
# Robot testlerini pytest üzerinden çalıştır
pytest tests/sunucu_saglik_testleri.robot -v
# Hem Python hem Robot testlerini birlikte çalıştır
pytest tests/ -v --tb=short
Robot Framework sonuçlarını programatik olarak işlemek için robot.api modülünü kullanabilirsiniz:
# scripts/sonuc_analiz.py
from robot.api import ExecutionResult, ResultVisitor
class BasarisizTestToplayici(ResultVisitor):
"""Başarısız testleri toplayan visitor sınıfı."""
def __init__(self):
self.basarisiz_testler = []
self.toplam = 0
self.basarili = 0
def visit_test(self, test):
self.toplam += 1
if test.status == 'FAIL':
self.basarisiz_testler.append({
'isim': test.name,
'mesaj': test.message,
'sure': test.elapsedtime
})
else:
self.basarili += 1
def sonuclari_analiz_et(output_xml_yolu):
"""output.xml dosyasını analiz ederek özet çıkarır."""
sonuc = ExecutionResult(output_xml_yolu)
toplayici = BasarisizTestToplayici()
sonuc.visit(toplayici)
print(f"n{'='*50}")
print(f"TEST SONUÇ ÖZETİ")
print(f"{'='*50}")
print(f"Toplam Test: {toplayici.toplam}")
print(f"Başarılı: {toplayici.basarili}")
print(f"Başarısız: {len(toplayici.basarisiz_testler)}")
if toplayici.basarisiz_testler:
print(f"nBaşarısız Testler:")
for test in toplayici.basarisiz_testler:
print(f" - {test['isim']}")
print(f" Hata: {test['mesaj'][:100]}...")
return len(toplayici.basarisiz_testler) == 0
if __name__ == '__main__':
import sys
xml_dosyasi = sys.argv[1] if len(sys.argv) > 1 else 'results/output.xml'
basarili = sonuclari_analiz_et(xml_dosyasi)
sys.exit(0 if basarili else 1)
CI/CD Pipeline Entegrasyonu
Testlerin CI/CD’ye entegrasyonu için minimal bir Makefile hazırlamak işleri hızlandırıyor:
# Makefile
.PHONY: test smoke regression clean report
ROBOT=robot
PYTEST=pytest
SONUC_DIR=results
TEST_DIR=tests
smoke:
$(ROBOT)
--outputdir $(SONUC_DIR)/smoke
--include smoke
--loglevel INFO
--report smoke_raporu.html
$(TEST_DIR)/
regression:
$(ROBOT)
--outputdir $(SONUC_DIR)/regression
--exclude skip
--loglevel DEBUG
--timestampoutputs
$(TEST_DIR)/
birim-testler:
$(PYTEST) tests/unit/ -v --cov=libraries --cov-report=html
tam-test:
$(MAKE) birim-testler
$(MAKE) smoke
$(MAKE) regression
python scripts/sonuc_analiz.py $(SONUC_DIR)/regression/output.xml
temizlik:
rm -rf $(SONUC_DIR)/
find . -name "*.pyc" -delete
find . -name "__pycache__" -type d -exec rm -rf {} +
rapor-sun:
python3 -m http.server 8888 --directory $(SONUC_DIR)/regression &
echo "Raporlar http://localhost:8888 adresinde"
Jenkins veya GitLab CI için tipik bir pipeline adımı:
# .gitlab-ci.yml içinden ilgili test stage
stages:
- test
robot_testleri:
stage: test
image: python:3.11-slim
before_script:
- pip install robotframework robotframework-requests robotframework-seleniumlibrary
script:
- robot --outputdir results --xunit xunit_output.xml tests/
after_script:
- python scripts/sonuc_analiz.py results/output.xml || true
artifacts:
when: always
paths:
- results/
reports:
junit: results/xunit_output.xml
expire_in: 7 days
allow_failure: false
Sık Yapılan Hatalar ve Bunlardan Kaçınma
Yıllarca Robot Framework kullanan biri olarak şu hataları defalarca gördüm:
- Her şeyi tek bir test dosyasına tıkmak. Bakımı imkânsız hale gelir. Suite bazlı mantıksal ayrım yapın.
- Keyword isimlerini kısaltmak. “KK” yerine “Kullanıcı Kaydı Tamamla” yazın. Testler kendi kendini belgelemelidir.
- Teardown yazmamak. Test başarısız olunca ortamı kirletir, sonraki testler etkilenir. Her kritik test için teardown şart.
- Hardcoded değerler. IP adresi, kullanıcı adı, URL gibi değerleri doğrudan test içine yazmak yerine değişken veya dışarıdan inject edilen parametre kullanın.
- Hata mesajlarını önemsememek.
Should Be Equalgibi assertion’lardamsg=parametresiyle açıklayıcı mesaj ekleyin. Gece 02:00’de incelenen hata raporu için bu küçük detay büyük fark yaratır.
Sonuç
Robot Framework, doğru kullanıldığında test otomasyonunu ekip genelinde paylaşılan bir sorumluluk haline getirebilir. Geliştiriciler Python kütüphaneleri yazar, QA mühendisleri bu kütüphaneleri kullanarak business language’da testler oluşturur, sistem yöneticileri de smoke testleri anlayıp yorumlayabilir. Bu hiyerarşi güzel çalışıyor.
pytest ile birlikte kullandığınızda ise elimde iki farklı silah oluyor: birim ve entegrasyon testleri için pytest’in esnekliği, sistem ve kabul testleri için Robot Framework’ün okunabilirliği. Bu iki aracı rakip değil tamamlayıcı olarak konumlandırmak, test stratejinizi çok daha sağlam temellere oturtacaktır.
Başlangıç için tavsiyem şu: Mevcut altyapınızın en kritik beş işlevini belirleyin ve bunlar için Robot Framework smoke testleri yazın. CI pipeline’ına bağlayın ve her deployment’ta otomatik koşturun. İlk hafta içinde bu testlerin değerini görürsünüz.
