Merhaba! API testlerini otomatize etmenin yollarını arıyorsanız, RestAssured kütüphanesi sizin için biçilmiş kaftan olabilir. Bu yazımızda, RestAssured’ın temellerini atarak, API test otomasyonu dünyasında nasıl güçlü bir müttefik haline geldiğini keşfedeceğiz. Uzun bir yazı olacak başlamadan önce bir kahve alın ve beraber adım adım ilerleyelim! ☕
GİRİŞ
RestAssured Nedir?
RestAssured, Java dilinde geliştirilmiş ücretsiz bir kütüphanedir ve özellikle RESTful API’larla yapılan HTTP isteklerini test etmek ve doğrulamak için kullanılır. Yazılım geliştiricileri ve test mühendisleri tarafından yaygın olarak tercih edilmektedir, çünkü RESTful servislerle iletişim kurmayı ve bu servisleri test etmeyi oldukça kolaylaştırır. RestAssured, basit, anlaşılır ve esnek bir programlama arayüzü sunar, bu da kullanıcıların hızlı ve etkili bir şekilde test senaryoları oluşturmasına olanak tanır. Ayrıca Gherkin tipi bir syntax yapısına sahip olduğu için BDD (Behavior-Driven Development) severler bu kütüphaneye hayran kalacaksınız.
RestAssured’ın temel özellikleri şunlardır:
- Kolay Kullanım: RestAssured, gerçekten kullanımı kolay bir syntax’a sahiptir. RESTful servislerle etkileşim kurmak artık çok daha basit. Karmaşık HTTP istekleri ve cevaplarıyla boğuşmadan test senaryolarını hızla oluşturabilirsiniz.
- Request ve Response İşleme: RestAssured, farklı HTTP metodları (GET, POST, PUT, DELETE vb.) ve çeşitli veri türleriyle (form parametreleri, header bilgileri, body verileri vb.) rahatlıkla çalışabilir. Ayrıca, istekleri ve cevapları detaylı bir şekilde inceleme imkanı sunar.
- Path ve Query Parametre Desteği: RESTful servislerle çalışırken sıkça kullanılan path parametreleri ve query parametreleri kolayca işleyebilirsiniz. Bu sayede, RestAssured ile path ve query parametrelerini kullanarak, farklı senaryolara uygun dinamik API istekleri oluşturabilir ve test edebilirsiniz. Bu esneklik, özellikle çeşitli durumlarda API testlerini daha kapsamlı bir şekilde gerçekleştirmenizi sağlayacaktır.
- JSON ve XML İşleme: RestAssured, RESTful API’larının yaygın olarak kullandığı JSON ve XML gibi veri formatları ile etkileşimi kolayca yönetir. Bu özellik, API’lerin cevaplarını anlamak, doğrulamak ve test senaryolarını oluşturmak açısından oldukça önemlidir.
- Otomasyon ve Entegrasyon: RestAssured, test otomasyon projelerinde kullanılmak üzere tasarlanmıştır. Bu nedenle, test senaryolarınızı otomatize etmek için popüler test otomasyon araçlarıyla (TestNG, JUnit vb.) ve CI/CD sürecine kolayca entegre edilebilir.
Ön Hazırlık
Java’da bir Maven projesi oluşturalım ve pom.xml dosyasına aşağıda gösterildiği gibi bağımlılıkları ekleyelim.TestNG framework’ünü kullanıyorum, ancak isterseniz farklı bir framework de seçebilirsiniz. İlerleyen bölümlerde ihtiyaç duyabileceğimiz ek bağımlılıkları da sizinle paylaşacağım.
<dependencies> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>5.4.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.8.0</version> <scope>test</scope> </dependency> </dependencies>
İlk Test
Şimdi src/test/java
klasörünün içine yeni bir package oluşturalım. Oluşturduğumuz package içine de bir class ekleyip, birlikte ilk test metodumuzu oluşturalım.
@Test public void firstTestScenario() { Response response = RestAssured.get("https://reqres.in/api/users?page=2"); Assert.assertEquals(response.getStatusCode(), 200); }
RestAssured.get("https://reqres.in/api/users?page=2")
: Bu satır, RestAssured kütüphanesini kullanarak belirtilen URL’ye bir HTTP GET isteği gönderir ve bu isteğin cevabını temsil eden birResponse
nesnesini döndürür.response.getStatusCode()
: Bu, HTTP cevabının durum kodunu alır. Örneğin, 200 OK, 404 Not Found gibi durum kodları olabilir.Assert.assertEquals(response.getStatusCode(), 200)
: Bu satırda, alınan cevabın durum kodunun 200 olduğunu doğrulamak için bir assert (doğrulama) ifadesi kullanılır. Eğer durum kodu 200 değilse, test başarısız olacaktır.
Bu isteği BDD sözdizimine uygun bir şekilde yazmak istersek;
@Test public void firstBddTestScenario() { given() .when() .get("https://reqres.in/api/users?page=2") .then() .statusCode(200) .log().body(); }
given()
: Bu, RestAssured’in BDD tarzında kullanımına aittir. Bu bölüm, test senaryosunun başlangıç koşullarını (given) belirtir.when()
: Bu bölüm, test senaryosundaki eylemi (when) belirtir. Yani, bir HTTP GET isteği yapılır.get("https://reqres.in/api/users?page=2")
: Bu satır, belirtilen URL’ye bir HTTP GET isteği yapar.then()
: Bu bölüm, test senaryosunun beklenen sonuçlarını (then) belirtir.statusCode(200)
: Bu satır, HTTP cevabının durum kodunun 200 (OK) olması gerektiğini belirtir.log().body()
: Response gövdesini loglamak için kullanılır. Bu sayede gerçekleşen HTTP cevabını daha ayrıntılı bir şekilde inceleyebilirsiniz. Bu bölümü geliştirme ve hata ayıklama aşamasında kullanmak faydalı olabilir. RestAssured kütüphanesinde body dışında headers, cookie, all gibi methodlarda bulunmaktadır ihtiyacınıza göre bu seçeneklerden de faydalanabilirsiniz.
RestAssured ile POST İsteği Nasıl Atılır?
RestAssured.baseURI = "https://reqres.in/api";
: Bu satır, testin yapılacağı API’nin temel URI’sini belirler.HashMap<String, Object> data = new HashMap<>();
: Bu satır, atılacak request için body data oluşturmak amacıyla kullanıldı, ilerleyen konularımızda çeşitli yöntemlerden (Excel, Pojo, Json File) faydalanıyor olacağız.post("/users")
: Bu satır, belirtilen URL’e bir HTTP POST isteği yapar.
@Test public void createUserTest() { baseURI = "https://reqres.in/api"; HashMap<String, Object> data = new HashMap<>(); data.put("name", "Yasin"); data.put("job", "Tester"); given() .body(data) .when() .post("/users") .then() .statusCode(201) .log().body(); }
Bu isteğin sonucunda, web servisin id
ve createdAt
değerlerini döndüğünü gözlemleyebiliriz.
{ "id": "687", "createdAt": "2023-12-25T07:35:07.206Z" }
RestAssured ile PUT/PATH/DELETE İsteği Nasıl Atılır?
put("/users/2")
: Bu satır, belirtilen URL’ye bir HTTP PUT isteği gönderir. “2” kullanıcının id bilgisini temsil eder. PATCH ve DELETE istekleri de aynı mantıkta çalışmaktadır.
@Test public void updateUserTest() { baseURI = "https://reqres.in/api"; HashMap<String, Object> data = new HashMap<>(); data.put("name", "Salih"); data.put("job", "Teacher"); given() .body(data) .when() .put("/users/2") .then() .statusCode(200) .log().body(); }
Gerçek hayatta, genellikle kullanıcının kimlik bilgisi, bu örnekte olduğu gibi manuel olarak verilmez. createUserTest() test metodu çalıştıktan sonra, response bilgisinde bulunan Id bilgisi kullanılarak update, delete gibi test metodları dinamik bir şekilde oluşturulur. Bu yöntemle, test senaryolarını gerçek ve dinamik verilerle oluşturmak mümkündür. Bir örnek ile açıklamaya çalışayım.
@Test(priority = 0) public void createUserTest(ITestContext context) { baseURI = "https://reqres.in/api"; HashMap<String, Object> data = new HashMap<>(); data.put("name", "Yasin"); data.put("job", "Tester"); Response response = given() .body(data) .when() .post("/users"); context.setAttribute("userId", response.jsonPath().getInt("id")); } @Test(priority = 1, dependsOnMethods = "createUserTest") public void updateUserTest(ITestContext context) { RestAssured.baseURI = "https://reqres.in/api"; HashMap<String, Object> data = new HashMap<>(); data.put("name", "Salih"); data.put("job", "Teacher"); String userId = (String) context.getAttribute("userId"); given() .body(data) .when() .put("/users/" + userId) .then() .statusCode(200) .log().body(); }
createUserTest
metodu, bir kullanıcı oluşturma isteği gönderir, kullanıcı oluşturulabilirse ID bilgisi ITestContext aracılığıyla saklanır. updateUserTest
metodu, createUserTest
metodunun tamamlanmasına bağımlı olarak çalışır ve önceki adımda elde edilen kullanıcı ID’sini kullanarak güncelleme işlemi yapar. ITestContext, TestNG tarafından sağlanan bir özelliktir ve test sınıflarında ve metodlarında kullanılabilir.
response.jsonPath().getInt("id")
ifadesi, RestAssured kütüphanesinde bir HTTP yanıtının JSON gövdesini analiz etmek için kullanılan bir yapıdır. Bu ifade, JSON yanıtındaki belirli bir alanın değerini alır.
Query ve Path Parametreleri
Query parametreleri, bir URL’nin sonuna eklenen parametrelerdir. Örneğin, /api/users?page=2&id=5
gibi bir URL’de “page” ve “id” query parametreleri bulunmaktadır.
Path parametreleri, URL’nin bir bölümüne eklenen ve genellikle dinamik verileri temsil eden parametrelerdir. Örneğin, /api/{mypath}
gibi bir URL’de “mypath” path parametresi bulunmaktadır. RestAssured’de quey ve path parametreleri şu şekilde eklenir:
@Test public void queryAndPathParamTest() { given() .pathParam("mypath", "users") .queryParam("page", 2) .queryParam("id", 5) .when() .get("https://reqres.in/api/{mypath}") .then() .statusCode(200) .log().body(); }
Bu test senaryosu çalıştırıldığında, ikinci sayfada Id bilgisi beş olan kullanıcının bilgilerini döner.
Cookie ve Header Yönetimi
RestAssured kütüphanesi, HTTP istekleri üzerinde çalışırken cookie’leri ve header’ları yönetmek için kullanışlı methodlara sahiptir.
Cookie Yönetimi
Cookie’ler, bir web sitesi ile tarayıcı arasında saklanan küçük veri parçalarıdır. Bu veri parçaları, web tarayıcısının kullanıcı hakkında bilgi saklamasına izin verir. RestAssured’de cookie’leri yönetmek için kullanılan bazı metotlar şunlardır:
cookie("name", "value")
: Bir HTTP isteğine cookie ekler.
given() .cookie("sessionID", "123456") .when() .get("/api/resource") .then() .statusCode(200);
response.getCookie("name")
: Verilen response nesnesi üzerindeki bir cookie’yi almak için bu method kullanılır. Tüm cookieleri almak içinse getCookies()
methodunda faydalanabilirsiniz.
Response response = given() .when() .get("/api/resource"); String cookie = res.getCookie("JSESSIONID"); Map<String, String> cookies_value = response.getCookies();
Header Yönetimi
HTTP başlıkları, bir isteğin veya yanıtın ek bilgilerini taşıyan veri parçalarıdır. RestAssured’de header’ları yönetmek için kullanılan bazı metotlar şunlardır:
header("headerName", "headerValue")
: Bir HTTP isteğine header ekler.
given() .header("Content-Type", "application/json") .when() .get("/api/resource") .then() .statusCode(200);
response.getHeader("name")
: Verilen response nesnesi üzerindeki belirtilen header tipinin değerini döner. Tüm header bilgisini almak isterseniz getHeaders()
methodunu kullanabilirsiniz.
Response response = given() .when() .get("/api/resource"); String header_value = response.getHeader("Content-Type"); Headers headers = response.getHeaders(); for (Header h : headers) { out.println(h.getName() + ": " + h.getValue()); }
Authentication Yöntemleri
Web servislerinde authentication (kimlik doğrulama), iki taraflı güven sağlamak amacıyla gerçekleştirilen bir süreçtir. Bu süreç, kullanıcıların veya sistemlerin gerçekten kim olduklarını doğrulama ve belirli kaynaklara (örneğin, API’lar, veritabanları) güvenli bir şekilde erişmelerini sağlama amacını taşır.
RestAssured, HTTP istekleri sırasında çeşitli kimlik doğrulama (authentication) yöntemlerini destekler. İşte RestAssured ile kullanılabilen bazı temel kimlik doğrulama yöntemleri:
Basic Authentication
Basic Authentication, kullanıcı adı ve şifre ile çalışır. RestAssured auth().basic
metodunu sağlar.
.body("authenticated", equalTo(true))
: HTTP yanıtının gövdesindeki belirli bir alanın (burada “authenticated”) değerini kontrol eder.
given() .auth().basic("postman", "password") .when() .get("https://postman-echo.com/basic-auth") .then() .statusCode(200) .body("authenticated", equalTo(true));
Digest Authentication
RestAssured, digest kimlik doğrulama için auth().digest
metodunu sağlar.
given() .auth().digest("postman", "password") .when() .get("https://postman-echo.com/basic-auth") .then() .statusCode(200) .body("authenticated", equalTo(true));
Preemptive Authentication
RestAssured, preemptive kimlik doğrulama için .auth().preemptive().basic
metodunu sağlar.
given() .auth().preemptive().basic("postman", "password") .when() .get("https://postman-echo.com/basic-auth") .then() .statusCode(200) .body("authenticated", equalTo(true));
Bearer Token Authentication
RestAssured kütüphanesinde bearer token kimlik doğrulama için header içerisine token bilgisi eklenerek istek gönderilmelidir.
.header("Authorization", MessageFormat.format("Bearer {0}", token))
: Bu satırda, HTTP isteği için başlık (header) eklenir. Bu başlık, GitHub API’ye yetkilendirme yapmak için kullanılır. MessageFormat.format
kullanılarak token değeri eklenmiştir.
String token = "ghp_"; given() .header("Authorization", MessageFormat.format("Bearer {0}", token)) .when() .get("https://api.github.com/user/repos") .then() .statusCode(200) .log().body();
OAuth Authentication
OAuth1.0 ve OAuth2.0 olmak üzere iki versiyonu bulunmaktadır. RestAssured .auth().oauth()
ve .auth().oauth2()
methodlarını sağlar.
given() .auth().oauth("consumerKey", "consumerSecret", "accessToken", "tokenSecret") .when() .get("url") .then() .statusCode(200);
String token = "ghp_d"; given() .auth().oauth2(token) .when() .get("https://api.github.com/user/repos") .then() .statusCode(200) .log().body();
API Key Authentication
RestAssured kütüphanesinde isteğe appid
anahtarı ve apiKey
değeri ile bir queryParam eklenmelidir.
given() .queryParam("appid", "apiKey") .when() .get("api.url") .then() .statusCode(200);
XML Response Doğrulama
RestAssured, XML doğrulama, bir HTTP yanıtının içindeki XML verilerinin belirli bir formata uygun olup olmadığını kontrol etme işlemidir. Aşağıdaki linke istek atarak sonucunda dönen xml verisini xmlPath().get()
methoduyla doğrulamaya çalışalım.
@Test public void validateXmlTest() { baseURI = "http://restapi.adequateshop.com/api/"; Response response = given() .pathParam("path", "Traveler") .queryParam("page", 2) .when() .get("{path}"); String pageNumber = response.xmlPath(). get("TravelerinformationResponse.page").toString(); Assert.assertEquals(pageNumber, "2"); String travelName = response.xmlPath(). get("TravelerinformationResponse.travelers.Travelerinformation[0].name"); Assert.assertEquals(travelName, "ASCAS"); }
response.xmlPath().get("TravelerinformationResponse.page")
ifadesi ile XML yanıtındaki “page” öğesinin değeri alınır.Assert.assertEquals(pageNumber, "2")
ifadesi ile bu değer “2” ile eşleştirilir ve doğrulama yapılır.response.xmlPath().get("TravelerinformationResponse.travelers.Travelerinformation[0].name")
ifadesi ile XML yanıtındaki ilk “travelers” öğesindeki ilk “name” öğesinin değeri alınır.Assert.assertEquals(travelName, "ASCAS")
ifadesi ile bu değer “ASCAS” ile eşleştirilir ve doğrulama yapılır.
Hamcrest kütüphanesinin bize sunduğu hasXpath()
methoduyla da XML üzerinde doğrulama işlemleri yapılabilir.
public void validateXmlTest() { given() .pathParam("path", "Traveler") .queryParam("page", 2) .when() .get("{path}") .then() .body(hasXPath("/TravelerinformationResponse/page", equalTo("2"))); }
JSON Response Doğrulama
RestAssured kullanarak, bir API isteğinden gelen yanıttaki JSON verilerini analiz edebilir ve bu verileri daha sonra doğrulama amaçlı kullanabilirsiniz. RestAssured içerisinde, JSON yanıtlarını işlemek için özel bir JsonPath
sınıfı bulunmaktadır. Bu sınıfı kullanarak JSON yollarını ve değerlerini daha ayrıntılı bir şekilde ele alabilirsiniz. Aşağıda, RestAssured ile bir HTTP GET isteği gönderdikten sonra JSON yanıtını nasıl ayrıştıracağımızı inceleyelim.
@Test public void parsingJsonResponseBodyTest() {; baseURI = "https://gorest.co.in/public/v2"; String TOKEN = "e095..."; Response response = given() .contentType(ContentType.JSON) .headers("Authorization", "Bearer " + TOKEN) .pathParam("id", 5850682) .when() .get("/users/{id}"); Assert.assertEquals(response.jsonPath().getInt("id"), 5850682); }
response
nesnesinin JSON yolu üzerindeki “id” adlı alanın değerini alır ve bu değeri 5850682
ile karşılaştırır. Eğer bu değerler eşit değilse, bir AssertionError
oluşturulacaktır. Eğer değerler eşitse, testimiz pass olarak sonuçlanacaktır. jsonPath sınıfının get(), getString(), getList() gibi bir çok methodu bulunmaktadır daha karmaşık sorgulama ve filtrelemeler için bu methodları kullanabilirsiniz.
Json obje yapısını kafanızda canlandırmak için yukarıdaki fotoğrafı paylaşıyorum. Görüldüğü gibi, en dışta Main Json objemiz bulunuyor. Bu obje içinde page
, per_page
gibi temel key-value bilgileri ve data
adında bir Json dizisi yer alıyor. Json dizisi ise birden fazla Json objesinden oluşuyor. Json dizisi içindeki bir değeri almak istiyorsanız, aşağıdaki kod bloğunu kullanabilirsiniz.
response.jsonPath().getString("data[0].first_name")
data dizisinin içerisindeki ilk json objesinin first_name
bilgisini almanızı sağlar.
Payload (Veri Kümesi) Oluşturmanın Farklı Yolları
Payload, bir isteğin veya yanıtın içinde taşınan veri veya bilgidir. Bu veri, genellikle JSON veya XML formatında olabilir, ancak bazen metin veya başka bir formatta da olabilir. Bu bölümde API isteğinde verinin nasıl farklı yollarla gönderilebildiğini işleyeceğiz. RestAssured ile POST İsteği Nasıl Atılır? bölümünde, HTTP POST isteği için payload oluşturmayı HashMap yapısı kullanarak göstermiştik hadi şimdi diğer yöntemlere de hızlıca göz atalım.
ORG.JSON Kütüphanesini Kullanarak
org.json
kütüphanesi, JSON (JavaScript Object Notation) verilerini oluşturmak, analiz etmek ve manipüle etmek için kullanılır. Kütüphaneyi kullanabilmek için pom.xml dosyanıza ilgili bağımlılığı eklememiz gerekmektedir.
<dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20231013</version> </dependency>
JSONObject jsonData = new JSONObject();
ile yeni bir JSON nesnesi oluşturulur.jsonData.put(...)
çağrıları ile JSON nesnesine kullanıcı bilgileri eklenir.body(jsonData.toString())
ile isteğe payload eklenir.toString()
metodu,JSONObject
‘i bir JSON stringine çevirir.
@Test public void orgJsonLibraryUsingTest() { baseURI = "https://gorest.co.in/public/v2"; JSONObject jsonData = new JSONObject(); jsonData.put("name", "Hasan"); jsonData.put("email", "hasan@test.com"); jsonData.put("gender", "Male"); jsonData.put("status", "active"); given() .contentType(ContentType.JSON) .headers("Authorization", "Bearer " + TOKEN) .body(jsonData.toString()) .when() .post("/users") .then().statusCode(201); }
POJO Sınıf Kullanarak
Bir önceki yöntemde, kullanıcı bilgilerini org.json kütüphanesinin sunduğu metotları kullanarak isteğin gövdesine eklemiştik. Bu seferki yöntemimizde ise User adında bir sınıf oluşturacağız. Sınıfımızın içerisinde alanlarımız (fields) ve bunlara erişmek için kullanılan getter-setter metotlarımız yer alacak.
POJO sınıfları genellikle ileride ek özellikler/metotlar veya alanlar (fields) eklemek için kolayca genişletilebilir. Bu, kodunuzu değişikliklere karşı daha esnek ve genişletilebilir hale getirir.
public class User { public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } String name; String gender; String email; String status; }
@Test public void pojoClassUsingTest() { baseURI = "https://gorest.co.in/public/v2"; User userData = new User(); userData.setName("Hasan"); userData.setEmail("hasan@abc.com"); userData.setGender("Male"); userData.setStatus("active"); given() .contentType(ContentType.JSON) .headers("Authorization", "Bearer " + TOKEN) .body(userData) .when() .post("/users") .then().statusCode(201); }
User userData = new User();
:User
adlı POJO sınıfından bir örnek oluşturulur. Bu örnek, yeni bir kullanıcı oluşturmak için kullanılacak verileri temsil eder.- POJO sınıfının setter metotları aracılığıyla kullanıcı verileri atanır.
.body(userData)
: Bu, gönderilecek isteğin gövdesine (body
) POJO sınıfındaki verileri ekler. RestAssured, otomatik olarak POJO sınıfını JSON formatına dönüştürür.
Harici JSON Dosyası Kullanarak
Bu yöntemimizde, isteğin gövdesine eklenecek olan payload için harici bir JSON dosyası oluşturacağız. readJsonFile()
metodunu kullanarak bu dosyayı okuyacak ve payload olarak göndereceğiz. Payload’ın harici bir JSON dosyasında bulunması, veri ve kodun ayrılmasına yardımcı olur. Bu sayede veriyi kolayca güncelleyebilir, değiştirebilir veya farklı senaryolar için farklı dosyalar kullanabilirsiniz.
readJsonFile methodunu yazabilmek için JsonUtiliy adında yeni bir class oluşturarak işe koyulalım.
public class JsonUtility { public static String path = Paths.get(System.getProperty("user.dir"), "src", "test", "resources", "JsonFiles").toString(); public static JSONObject readJsonFile(String file) { JSONObject jsonData = null; try (FileReader fileReader = new FileReader(new File(Paths.get(path, file).toString()))) { JSONTokener jsonTokener = new JSONTokener(fileReader); jsonData = new JSONObject(jsonTokener); } catch (FileNotFoundException e) { System.out.println("File not found --> " + file); e.printStackTrace(); } catch (Exception e) { System.out.println("An error occurred while reading the JSON file."); e.printStackTrace(); } return jsonData; } }
- “src/test/resources” dosya yolunun altına JsonFiles adında bir klasör oluşturun, burada payload bilgisini tutacağız.
readJsonFile
metodu, belirtilen JSON dosyasını okuyan ve birJSONObject
döndüren bir metottur.FileReader
veJSONTokener
kullanılarak JSON dosyası okunur veJSONObject
‘e dönüştürülür.- Okunan
JSONObject
ya danull
(eğer hata oluşmuşsa) döndürülür.
JsonFiles klasörünün içerisine userData.json uzantılı bir dosya oluşturun.
{ "name": "Hasan", "email": "hasan@abc.net", "gender": "Male", "status": "active" }
body(readJsonFile("userData.json").toString())
ifadesi ile userData.json
dosyasından okunan JSON verisi, isteğin gövdesine eklenmiştir.
@Test public void externalJsonFileTest() { baseURI = "https://gorest.co.in/public/v2"; given() .contentType(ContentType.JSON) .headers("Authorization", "Bearer " + TOKEN) .body(readJsonFile("userData.json").toString()) .when() .post("/users") .then().statusCode(201); }
Excel Dosyası Kullanarak
Bu yöntemde, isteğin gövdesine eklenecek olan payload için harici bir Excel dosyası oluşturacağız. Yazacağımız Excel okuma metoduyla .xls ve .xlsx uzantılı dosyayı okuyup, payload olarak göndereceğiz. Harici JSON dosyası okuma yöntemi için söylediklerimiz bu yöntemde geçerlidir; payload’ın harici bir Excel dosyasında bulunması, veri ve kodun ayrılmasına yardımcı olur. Bu sayede veriyi kolayca güncelleyebilir, değiştirebilir veya farklı senaryolar için farklı dosyalar kullanabilirsiniz.
Ancak, bu yöntemin de dezavantajları var. Excel dosyalarının okunması ve işlenmesi, bazen diğer formatlara göre daha karmaşık olabilir. Ayrıca, dosyanın okunabilir olabilmesi için belirli bir düzeni ve formatı koruması gerekebilir. Bu durum, değişen veya karmaşık veri yapıları ile çalışıldığında sorunlara neden olabilir.
ExcelUtility
adında yeni bir class oluşturarak devam edelim.
- Constructor (
ExcelUtility(String path)
)- Bu constructor, Excel dosyasının yolu (
path
) ile başlatılır.
- Bu constructor, Excel dosyasının yolu (
getRowCount(String sheetname)
- Belirli bir sayfa (sheet) üzerindeki toplam satır sayısını döndürür.
- Dosya işlemleri tamamlandıktan sonra dosyaları ve akışları kapatır.
getCellCount(String sheetname, int rownum)
- Belirli bir sayfa ve satır üzerindeki toplam hücre sayısını döndürür.
- Dosya işlemleri tamamlandıktan sonra dosyaları ve akışları kapatır.
getCellData(String sheetname, int rownum, int colnum)
- Belirli bir sayfa, satır ve sütun konumundaki hücrenin verisini döndürür.
- Dosya işlemleri tamamlandıktan sonra dosyaları ve akışları kapatır.
public class ExcelUtility { public FileInputStream fileInputStream; public FileOutputStream fileOutputStream; public XSSFWorkbook workbook; public XSSFSheet sheet; public XSSFRow row; public XSSFCell cell; public CellStyle cellStyle; String path; public ExcelUtility(String path) { this.path = path; } public int getRowCount(String sheetname) throws IOException { fileInputStream = new FileInputStream(path); workbook = new XSSFWorkbook(fileInputStream); sheet = workbook.getSheet(sheetname); int rowcount = sheet.getLastRowNum(); workbook.close(); fileInputStream.close(); return rowcount; } public int getCellCount(String sheetname, int rownum) throws IOException { fileInputStream = new FileInputStream(path); workbook = new XSSFWorkbook(fileInputStream); sheet = workbook.getSheet(sheetname); row = sheet.getRow(rownum); int cellcount = row.getLastCellNum(); workbook.close(); fileInputStream.close(); return cellcount; } public String getCellData(String sheetname, int rownum, int colnum) throws IOException { fileInputStream = new FileInputStream(path); workbook = new XSSFWorkbook(fileInputStream); sheet = workbook.getSheet(sheetname); row = sheet.getRow(rownum); cell = row.getCell(colnum); DataFormatter dataFormatter = new DataFormatter(); String data; try { data = dataFormatter.formatCellValue(cell); } catch (Exception exception) { exception.getMessage(); data = ""; ; } workbook.close(); fileInputStream.close(); return data; } }
- “src/test/resources” dosya yolunun altına testData adında bir klasör oluşturun.
- testData klasörünün altına bir tane Excel dosyası oluşturun ve dosyayı aşağıdaki gibi hazırlayın.
Excelden okuduğumuz verileri test metoduna gönderebilmek için DataProviders
adında yeni bir class oluşturalım.
import org.testng.annotations.DataProvider; import java.nio.file.Paths; import java.nio.file.Path; import java.io.IOException; public class DataProviders { public static String path = Paths.get(System.getProperty("user.dir"), "src", "test", "resources", "testData", "userData.xlsx").toString(); public static String sheetName = "Sheet1"; @DataProvider(name = "user-data") public String[][] getAllUserData() throws IOException { ExcelUtility excelUtility = new ExcelUtility(path); int rownum = excelUtility.getRowCount(sheetName); int colnum = excelUtility.getCellCount(sheetName, 1); String payload[][] = new String[rownum][colnum]; for (int i = 1; i <= rownum; i++) { for (int j = 0; j < colnum; j++) { payload[i - 1][j] = excelUtility.getCellData(sheetName, i, j); } } return payload; } }
- Excel dosyasının yolu,
Paths.get
metodu kullanılarak belirlenir ve platform bağımsız bir şekilde birleştirilir. @DataProvider
anotasyonu, bu metodu TestNG’e bir veri sağlayıcı olarak tanımlar.getRow
vegetCellCount
metodlarıyla Excel sayfasındaki toplam satır ve sütun sayıları alınır.
@Test(dataProvider = "user-data", dataProviderClass = DataProviders.class) public void externalExelFileTest(String[] userData) { baseURI = "https://gorest.co.in/public/v2"; User user = new User(); user.setName(userData[0]); user.setGender(userData[1]); user.setEmail(userData[2]); user.setStatus(userData[3]); given() .contentType(ContentType.JSON) .headers("Authorization", "Bearer " + TOKEN) .body(user) .when() .post("/users") .then().statusCode(201); }
dataProvider
ile, veri sağlayıcının adı belirtilir (user-data
).dataProviderClass
ile, veri sağlayıcının bulunduğu sınıf belirtilir (DataProviders.class
).externalExcelFileTest
metodu,user-data
adlı veri sağlayıcısından alınan bir dizi (String[] userData
) ile çalışır.- Bu dizi,
DataProviders
sınıfındakigetAllUserData
metodundan gelir ve her bir dizi, bir kullanıcıya ait bilgileri içerir. .body(user)
: HTTP isteğinin gövdesineUser
objesi eklenir.
[BONUS] JUnit5 Kullanarak
JUnit 5 ile birlikte gelen @ParameterizedTest
ve @CsvSource
anatasyonlarını kullanarak parametreli test metodları oluşturabilirsiniz. @CsvSource
kullanılarak her bir satır, bir test çağrısı için giriş parametrelerini temsil eder. @ParameterizedTest
ise test metodunun parametreli bir test olarak çalıştırılmasını sağlar. Bu sayede, aynı test kodunu farklı giriş verileriyle tekrar kullanabilirsiniz.
Öncelikle Maven bağımlılığını ekleyelim;
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-params</artifactId> <version>5.8.1</version> <scope>test</scope> </dependency>
@ParameterizedTest
: Bu anotasyon, parametreli bir test metodu olduğunu belirtir. Yani, bu metodun belirli parametre setleri ile birden çok kez çalıştırılmasını sağlar.@CsvSource
: Bu anotasyon, CSV formatındaki verileri temsil eder. Her satır, bir test çağrısı için giriş parametrelerini içerir. Yani, bu örnekte iki farklı kullanıcı için dört parametre seti bulunmaktadır.csvSourceParameterizing
Metodu: Bu metodun adı ve parametreleri,@ParameterizedTest
ve@CsvSource
ile ilişkilendirilmiştir. Bu metodun parametreleri, CSV kaynağından alınan verileri temsil eder (name, email, gender, status).HashMap<String, String> variables = new HashMap<>();
: Bu satırda, API isteği için kullanılacak parametrelerin tutulduğu birHashMap
oluşturulur..body(variables)
: Bu, isteğin gövdesine, önceden oluşturulanvariables
HashMap’ini ekler. Bu, API’ye gönderilecek JSON verilerini temsil eder.
@ParameterizedTest @CsvSource({ "Hasan, hasan@asd.com.be, Male, active", "Yasin, yasin@asd.com.be, Male, active" }) public void csvSourceParameterizing(String name, String email, String gender, String status) { RestAssured.useRelaxedHTTPSValidation(); baseURI = "https://gorest.co.in/public/v2"; HashMap<String, String> variables = new HashMap<>(); variables.put("name", name); variables.put("email", email); variables.put("gender", gender); variables.put("status", status); given() .contentType(ContentType.JSON) .headers("Authorization", "Bearer " + TOKEN) .body(variables) .when() .post("/users") .then().statusCode(201); }
Olası Hatalar
Testlerinizi çalıştırdığınızda aşağıdaki hata mesajını alıyorsanız, test methodunuzun en başına RestAssured.useRelaxedHTTPSValidation()
komutunu ekleyin.
Bu komut, RestAssured kütüphanesinde HTTPS üzerinden yapılan isteklerde SSL sertifikası doğrulamasını kapatır. Bu, genellikle geliştirme veya test aşamasında kullanışlıdır, çünkü bazen geliştirme veya test sunucularında geçerli bir SSL sertifikası olmayabilir veya self-signed bir sertifika kullanılabilir.
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Sonuç
RestAssured kütüphanesiyle API testine dair bir rehberi tamamladık. Bu yazıyı okuduğunuz için teşekkür ederim. Umarım, RestAssured’in gücünü anlamanıza ve yazılım projelerinizde daha etkili API testleri oluşturmanıza yardımcı olabilmişimdir.
Sormak istediğiniz sorular, paylaşmak istediğiniz deneyimler veya keşfetmek istediğiniz yeni konular varsa, lütfen benimle iletişime geçmekten çekinmeyin.
Eğitim sırasında kullandığım örnek kod bloklarına github hesabımdan ulaşabilirsiniz.
Sağlıklı günler dilerim.